I'm not afraid of MV* in JavaScript

I'm not afraid of MV* in JavaScript

Sasha Shinkevich (@neesoglasnaja)

About me

Flux

          

Redux

              

bit.ly/CPH-JS-MV

Example

TodoList


No patterns

1. HTML

What is wrong

Benefits of MV*

MVC

MVC

MVC

MVC

MVC

MVC

MVC

MVC

MVC

MVC

MVC

MVC

Example MVC

MVC: HTML

<!-- ... -->    <body>       <script src="js/utils.js"></script>       <script src="js/models.js"></script>       <script src="js/views.js"></script>       <script src="js/controllers.js"></script>       <script src="js/app.js"></script>    </body></html>

MVC: HTML

<!-- ... -->    <body>       <script src="js/utils.js"></script>       <script src="js/models.js"></script>       <script src="js/views.js"></script>       <script src="js/controllers.js"></script>       <script src="js/app.js"></script>    </body></html>

MVC: app.js

var list = new ListController();

MVC: HTML

<!-- ... -->    <body>       <script src="js/utils.js"></script>       <script src="js/models.js"></script>       <script src="js/views.js"></script>       <script src="js/controllers.js"></script>       <script src="js/app.js"></script>    </body></html>

MVC: controllers.js

function ListController() {    var model = new TasksModel();    var view = new ListView(model);    view.addCreateTaskHandler(function(taskTitle) { ... });    view.addCheckedHandler(function(id) { ... });}

MVC: controllers.js

function ListController() {    var model = new TasksModel();    var view = new ListView(model);    view.addCreateTaskHandler(function(taskTitle) { ... });    view.addCheckedHandler(function(id) { ... });}

MVC: HTML

<!-- ... -->    <body>       <script src="js/utils.js"></script>       <script src="js/models.js"></script>       <script src="js/views.js"></script>       <script src="js/controllers.js"></script>       <script src="js/app.js"></script>    </body></html>

MVC: views.js

function ListView(model) {    var html = $( ... );    customEvents.registerEvent('UpdateList');    customEvents.addEventListener('UpdateList', function() { ... });    return {        addCreateTaskHandler: function(handler) { ... },        addCheckedHandler: function(handler) { ... }    };}

MVC: views.js

function ListView(model) {    var html = $( ... );    customEvents.registerEvent('UpdateList');    customEvents.addEventListener('UpdateList', function() { ... });    return {        addCreateTaskHandler: function(handler) { ... },        addCheckedHandler: function(handler) { ... }    };}

MVC: views.js

function ListView(model) {    var html = $( ... );    customEvents.registerEvent('UpdateList');    customEvents.addEventListener('UpdateList', function() { ... });    return {        addCreateTaskHandler: function(handler) { ... },        addCheckedHandler: function(handler) { ... }    };}

MVC: HTML

 <!-- ... -->    <body>       <script src="js/utils.js"></script>       <script src="js/models.js"></script>       <script src="js/views.js"></script>       <script src="js/controllers.js"></script>       <script src="js/app.js"></script>    </body></html>

MVC: models.js

function TasksModel() {    return {        data: {},        getAll: function() { ... },        addItem: function(name) { ... },        deleteItem: function(id) { ... },    };};

MVC: models.js

addItem: function(name) {    this.data[(new Date()).getTime()] = name;    customEvents.dispatchEvent('UpdateList');}

MVC: Example App

MVP

MVP

MVP

MVP

MVP

MVP

MVP

MVP

MVP

MVP

Example MVP

MVP: HTML

 <!-- ... -->   <body>      <script src="js/utils.js"></script>      <script src="js/models.js"></script>      <script src="js/views.js"></script>      <script src="js/presenters.js"></script>      <script src="js/app.js"></script>    </body></html>

MVP: HTML

 <!-- ... -->   <body>      <script src="js/utils.js"></script>      <script src="js/models.js"></script>      <script src="js/views.js"></script>      <script src="js/presenters.js"></script>      <script src="js/app.js"></script>    </body></html>

MVP: app.js

var list = new ListPresenter();

MVP: HTML

 <!-- ... -->   <body>      <script src="js/utils.js"></script>      <script src="js/models.js"></script>      <script src="js/views.js"></script>      <script src="js/presenters.js"></script>      <script src="js/app.js"></script>    </body></html>

MVP: presenters.js

function ListPresenter() {    var model = new TasksModel();    var view = new ListView(model.getAll());    view.addCreateTaskHandler(function(taskTitle) { ... });    view.addCheckedHandler(function(id) { ... });    customEvents.registerEvent('UpdateList');    customEvents.addEventListener('UpdateList', function() { ... });}

MVP: HTML

 <!-- ... -->   <body>      <script src="js/utils.js"></script>      <script src="js/models.js"></script>      <script src="js/views.js"></script>      <script src="js/presenters.js"></script>      <script src="js/app.js"></script>    </body></html>

MVP: views.js

function ListView(data) {    var html = $( ... );    return {        addCreateTaskHandler: function(handler) { ... },        addCheckedHandler: function(handler) { ... },        updateView: function(data) { ... }    };}

MVP: Example App

MVVM

Data binding

Each data change is reflected automatically by the elements that are bound to the data

MVVM

Example MVVM

Knockout.js

Open-source framework that implements Model-View-ViewModel and data binding in Javascript.

MVVM: HTML

    <body>       <!-- HTML -->       <script src="js/knockout-3.4.0.min.js"></script>       <script src="js/viewmodel.js"></script>    </body></html>

MVVM: HTML

<form data-bind="submit: addItem">    <ul data-bind="foreach: items">        <li>            <label data-bind="click: $parent.removeItem">                <input type="checkbox">                <span data-bind="text: $data"></span>            </label>        </li><!--      ...      -->

MVVM: HTML

    <body>       <!-- HTML -->       <script src="js/knockout-3.4.0.min.js"></script>       <script src="js/viewmodel.js"></script>    </body></html>

MVVM: viewmodel.js

var ListViewModel = function(items) {    return {       items: ko.observableArray(items),       itemToAdd: ko.observable(""),       addItem: function() { ... },       removeItem: function() { ... },    };};ko.applyBindings(new ListViewModel([]));

MVVM: viewmodel.js

var ListViewModel = function(items) {    return {       items: ko.observableArray(items),       itemToAdd: ko.observable(""),       addItem: function() { ... },       removeItem: function() { ... },    };};ko.applyBindings(new ListViewModel([]));

MVVM: viewmodel.js

var ListViewModel = function(items) {    return {       items: ko.observableArray(items),       itemToAdd: ko.observable(""),       addItem: function() { ... },       removeItem: function() { ... },    };};ko.applyBindings(new ListViewModel([]));

MVVM: Example App

What to choose?

Further reading

In the end

Questions?