如何将把手与骨架整合在一起

时间:2017-01-27 10:57:22

标签: javascript html backbone.js handlebars.js

我有一个简单的单页面应用程序,供我自己学习。该页面包含我提供的所有服务的UL。此列表来自JSON。每个服务旁边都有一个价格,还有一个用户可以选择的复选框。

在列表下方,所选服务的总价格值。基于此,你能告诉我我做错了什么吗?我正在尝试将服务列表集成为车把模板。 这是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="http://localhost/backbone-demo/assets/css/style.css" rel="stylesheet" />

</head>

<body>

    <form id="main" method="post" action="submit.php">
        <h1>My Services</h1>
        <div id="serviceTable"></div>
            <ul id="services">              
        <script id="services-template" type="text/x-handlebars-template">
          <!-- The services will be inserted here via handlebars-->

          {{#each services}}
          <li>
              <input type="checkbox" value="1" name="{{title}}"/> {{title}}
              <span>${{price}} </span>
          </li>
          {{/each}}

        </script>
            </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="http://localhost/backbone-demo/assets/js/libs/underscore.min.js"></script>
    <script src="http://localhost/backbone-demo/assets/js/libs/backbone.min.js"></script>
    <script src="http://localhost/backbone-demo/assets/js/libs/handlebars.js"></script>
    <script src="http://localhost/backbone-demo/assets/js/script.js"></script>
</body>

这是Javascript:

$(function(){

// Create a model for the services
var Service = Backbone.Model.extend({

    // Will contain three attributes.
    // These are their default values

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

    // Helper function for checking/unchecking a service
    toggle: function(){
        this.set('checked', !this.get('checked'));
    }
});


// Create a collection of services
var ServiceList = Backbone.Collection.extend({

    // Will hold objects of the Service model
    model: Service,

    // Return an array only with the checked services
    getChecked: function(){         
        return this.where({checked:true});
    }
});

//Retrieve the list of services
$.ajax({
    type: "GET",
    url: "assets/services.json",
    async: true,
    success: function(response){
        // Prefill the collection with a number of services.            
        var services = new ServiceList(response);                   
        var ServiceView = Backbone.View.extend({
            tagName: 'li',

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

            initialize: function(){

                // Set up event listeners. The change backbone event
                // is raised when a property changes (like the checked field)                   
                this.listenTo(services, 'change', this.render);
            },

            render: function(){
                var tpl = Handlebars.compile($("#services-template").html());
                //console.log(this.$el.selector);
                this.$el.html(tpl({services: services.toJSON()}));
                //console.log(this.$el);
                $('#serviceTable').append(this.$el);

                //document.getElementById('serviceTable').innerHTML = serviceData;
                // Create the HTML                  
                /* this.$el.html('<input type="checkbox" value="1" name="' + this.model.get('title') + '" /> ' + this.model.get('title') + '<span>$' + this.model.get('price') + '</span>');
                this.$('input').prop('checked', this.model.get('checked')); */

                // Returning the object is a good practice
                // that makes chaining possible
                return this;
            },

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

        // The main view of the application
        var App = Backbone.View.extend({

            // Base the view on an existing element
            el: $('#main'),

            initialize: function(){

                // Cache these selectors
                this.total = $('#total span');
                this.list = $('#services');

                // Listen for the change event on the collection.
                // This is equivalent to listening on every one of the 
                // service objects in the collection.
                this.listenTo(services, 'change', this.render);


                // Create views for every one of the services in the
                // collection and add them to the page

                services.each(function(service){

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

                }, this);   // "this" is the context in the callback
            },

            render: function(){

                // Calculate the total order amount by agregating
                // the prices of only the checked elements

                var total = 0;
                console.log(services.getChecked());

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

                // Update the total price
                this.total.text('$'+total);

                return this;

            }

        });

        new App();

    }
});

});

1 个答案:

答案 0 :(得分:0)

以下是您的代码的可行片段。您已经为集合中的每个服务定义了ServiceView,但是在此视图中,您正在使用整个集合,而不是this.model并且您的把手模板具有for循环它

这意味着您最终会显示集合的次数与集合中的模型一样多。下面的示例重复列表两次,因为列表中有2条记录。

有两种可能的解决方案:

  • 将您的ServiceView重命名为ServicesView并删除App初始化中的循环。

  • 移除模板中的循环并将通话更改为this.$el.html(tpl(this.model.toJSON()));

&#13;
&#13;
// Create a model for the services
var Service = Backbone.Model.extend({

    // Will contain three attributes.
    // These are their default values

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

    // Helper function for checking/unchecking a service
    toggle: function(){
        this.set('checked', !this.get('checked'));
    }
});


// Create a collection of services
var ServiceList = Backbone.Collection.extend({

    // Will hold objects of the Service model
    model: Service,

    // Return an array only with the checked services
    getChecked: function(){         
        return this.where({checked:true});
    }
});

//Retrieve the list of services
$.ajax({
    type: "GET",
    url: "http://www.mocky.io/v2/588b429d300000d11afa8d97",
    async: true,
    success: function(response){
        // Prefill the collection with a number of services.
        var services = new ServiceList(response);                   
        var ServiceView = Backbone.View.extend({
            tagName: 'li',

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

            initialize: function(){

                // Set up event listeners. The change backbone event
                // is raised when a property changes (like the checked field)                   
                this.listenTo(services, 'change', this.render);
            },

            render: function(){
                var tpl = Handlebars.compile($("#services-template").html());
                //console.log(this.$el.selector);
                this.$el.html(tpl({services: services.toJSON()}));
                //console.log(this.$el);
                $('#serviceTable').append(this.$el);

                //document.getElementById('serviceTable').innerHTML = serviceData;
                // Create the HTML                  
                /* this.$el.html('<input type="checkbox" value="1" name="' + this.model.get('title') + '" /> ' + this.model.get('title') + '<span>$' + this.model.get('price') + '</span>');
                this.$('input').prop('checked', this.model.get('checked')); */

                // Returning the object is a good practice
                // that makes chaining possible
                return this;
            },

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

        // The main view of the application
        var App = Backbone.View.extend({

            // Base the view on an existing element
            el: $('#main'),

            initialize: function(){

                // Cache these selectors
                this.total = $('#total span');
                this.list = $('#services');

                // Listen for the change event on the collection.
                // This is equivalent to listening on every one of the 
                // service objects in the collection.
                this.listenTo(services, 'change', this.render);


                // Create views for every one of the services in the
                // collection and add them to the page

                services.each(function(service){

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

                }, this);   // "this" is the context in the callback
            },

            render: function(){

                // Calculate the total order amount by agregating
                // the prices of only the checked elements

                var total = 0;
                console.log(services.getChecked());

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

                // Update the total price
                this.total.text('$'+total);

                return this;

            }

        });

        new App();
      }
  });
&#13;
<form id="main" method="post" action="submit.php">
        <h1>My Services</h1>
        <div id="serviceTable"></div>
            <ul id="services">              
        <script id="services-template" type="text/x-handlebars-template">
          <!-- The services will be inserted here via handlebars-->

          {{#each services}}
          <li>
              <input type="checkbox" value="1" name="{{title}}"/> {{title}}
              <span>${{price}} </span>
          </li>
          {{/each}}

        </script>
            </ul>

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

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

    </form>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.3.3/backbone-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.6/handlebars.min.js"></script>
&#13;
&#13;
&#13;