Применение MVC на стороне клиента становится популярным, т.к. браузерные приложения становятся все более сложными. Фреймворки позволяют организовать JavaScript код используя MVC. Backbone.js является одним из самых популярных фреймворков подобного рода и наиболее часто выбираемым среди остальных.


Сегодня мы сделаем форму выбора услуг по списку на Backbone.js. Итоговая стоимость будет рассчитываться в реальном времени исходя из стоимости выбранных услуг.


Что такое Backbone.js

Это фреймворк, который вносит структурность в веб-приложения давая возможность использовать модели, коллекции и виды. Данные на сервер поступают в виде REST JSON, и могут автоматически выбирать и сохранять данные. В этом уроке мы не будем отправлять данные на сервер — все будет храниться на стороне клиента. Кстати, Backbone.js не зависит и не заменят jQuery, так что вместе они работают отлично! Не стоит забывать о том, что backbone.js — это не волшебная палочка, которая сделает все за вас. Конечный результат и структура зависит только от вас. Организация кода может быть ужасной, если вы не знакомы с MVC. Так же, не стоит использовать фреймворк для небольших проектов, где пара строк jQuery могут решить вашу задачу. В этом уроке мы познакомимся с фундаментальными возможностями backbone.js, которые есть у этого фреймворка под капотом.


Что мы будем создавать

My Services

total: $0


Шаг 1. HTML

Мы начинаем с обычного HTML5 документа. В данном примере мы не стали реализовывать работу html5 в браузере IE.

index.html

<!DOCTYPE html>
<html>

    <head>
        <meta charset="utf-8" />
        <title>Your first Backbone.js App | Tutorialzine </title>

        <!-- Google web fonts -->
        <link href="http://fonts.googleapis.com/css?family=PT+Sans:400,700" rel='stylesheet' />

        <!-- The main CSS file -->
        <link href="assets/css/style.css" rel="stylesheet" />

    </head>

    <body>

        <form id="main" method="post" action="submit.php">
            <h1>My Services</h1>

            <ul id="services">
                <!-- The services will be inserted here -->
            </ul>

            <p id="total">total: <span>$0</span></p>

            <input type="submit" id="order" value="Order" />

        </form>

        <!-- JavaScript Includes -->
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
        <script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.4.4/underscore-min.js"></script>
        <script src="//cdnjs.cloudflare.com/ajax/libs/backbone.js/1.0.0/backbone-min.js"></script>

        <script src="assets/js/script.js"></script>

    </body>
</html>

Основной элемент на странице — это форма. UL внутри служит для списка услуг, а параграф #total отображает итоговую стоимость выбранных услуг.

Перед тем, как закрыть </body> я добавил jQuery, Backbone.js, и библиотеку Underscore (backbone зависит от ее функций). Последним идет файл скрипта script.js. Готовый скрипт ниже.


Шаг 2. JavaScript

  1. Сначала мы создадим модель для наших услуг. Она будет содержать свойства для имени, цены и проверки статуса (checked) — выбрана наша услуга или нет. Объект этого класса будет создан для каждой услуги, которую мы предлагаем;
  2. Затем мы создадим коллекцию Backbone. С помощью коллекций становится достаточно просто отслеживать те или иные события, производимые над объектами класса. В больших приложениях вам будет необходимо отслеживать, когда элементы добавляются или удаляются из коллекций и обновляются виды (views). В нашем же случае элементы коллекции преопределены, мы ничего добавлять не будем. Нам необходимо только отслеживать изменения и менять HTML в этой зависимости. Тут мы отслеживаем события при клике и изменении свойства модели.
  3. После этого мы определим виды (или шаблоны) для наших услуг. Каждый вид будет привязан к нашей модели и отправлять ее свойства в HTML.
  4. Наконец, мы создадим главный шаблон, который будет содержать в себе все наши услуги из коллекции и создавать виды (шаблоны) для них. Тут так же отслеживается событие на изменения в коллекции и обновляется итоговая стоимость.

Файл: script.js

$(function(){

    var Service = Backbone.Model.extend({

        defaults:{
            title: 'My service',
            price: 100,
            checked: false
        },

        toggle: function(){
            this.set('checked', !this.get('checked'));
        }
    });

    var ServiceList = Backbone.Collection.extend({

        model: Service,

        getChecked: function(){
            return this.where({checked:true});
        }
    });

    var services = new ServiceList([
        new Service({ title: 'web development', price: 200}),
        new Service({ title: 'web design', price: 250}),
        new Service({ title: 'photography', price: 100}),
        new Service({ title: 'coffee drinking', price: 10})
    ]);

    var ServiceView = Backbone.View.extend({
        tagName: 'li',

        events:{
            'click': 'toggleService'
        },

        initialize: function(){

            this.listenTo(this.model, 'change', this.render);
        },

        render: function(){

            this.$el.html('<input type="checkbox" name="' + this.model.get('title') + '" value="1" /> ' + this.model.get('title') + '<span>$' + this.model.get('price') + '</span>');
            this.$('input').prop('checked', this.model.get('checked'));

            return this;
        },

        toggleService: function(){
            this.model.toggle();
        }
    });

    var App = Backbone.View.extend({

        el: $('#main'),

        initialize: function(){

            this.total = $('#total span');
            this.list = $('#services');

            this.listenTo(services, 'change', this.render);

            services.each(function(service){

                var view = new ServiceView({ model: service });
                this.list.append(view.render().el);

            }, this);
        },

        render: function(){

            var total = 0;

            _.each(services.getChecked(), function(elem){
                total += elem.get('price');
            });

            this.total.text('$'+total);

            return this;
        }
    });

    new App();

});


Готово!

Наше небольшое приложение завершено. Надеюсь, что этот обзор даст вам понять, что Backbone.js очень функциональный фреймворк.