简体   繁体   中英

Backbone List View / Rendering List View Items

I am pretty new to Backbone.js. Please see my code for what I reference here. I have a View that is supposed to show a Collection of 'Stock' Models. This View is called 'StockDashboardView'. Each of the Stock Models that this View needs to can be shown with the 'StockDashboardItemView'. Before each StockDashboardItemView renders though, it's respective Stock Model needs to fetch some data (make a request for stock prices) so that the StockDashboardItemView can use the data to draw a graph. The StockDashboardView loops through each of the Stock Models and creates a StockDashboardItemView for each one. I should be getting 5 different graphs with different company datapoints in each. But all the graphs are the same, which means each of the 5 StockDashboardItemViews has the same model somehow. I know my fetch/looping logic is wrong but I don't know how or why. I also tried fetching in the individual StockDashboardItemViews instead of the StockDashboardView (see commented out code). Looking in my console.log statements I see the following print statements: (the collection has 5 models). Could someone please help me fix my logic? Thank you

----------1--------

----------1--------

----------1--------

----------1--------

----------1--------

----------2--------

----------3--------

----------2--------

----------3--------

----------2--------

----------3--------

----------2--------

----------3--------

----------2--------

----------3--------

            window.StockDashboardView = Backbone.View.extend({

                initialize: function () {
                    this.render();
                },

                render: function () {
                    var stocks = this.model.models;
                    var len = stocks.length;
                    var startPos = (this.options.page - 1) * 8;
                    var endPos = Math.min(startPos + 8, len);

                    $(this.el).html('<ul class="thumbnails"></ul>');
                    for (var i = startPos; i < endPos; i++) {
                        console.log("----------1--------");
                        var stock = stocks[i];
                        stock.set("_id", stocks[i].toJSON()["tickerSymbol"]);
                        stock.fetch({success: function(model, response, options){
                            stock.set("data", response);
                            // set interactivity to false
                            console.log("-----------2---------");
                            $('.thumbnails', this.el).append(new StockDashboardItemView({model: stock}).render().el);
                        }});

                    }

                    $(this.el).append(new Paginator({model: this.model, page: this.options.page}).render().el);

                    return this;
                }
            });

            window.StockDashboardItemView = Backbone.View.extend({

                tagName: "li",

                initialize: function () {
                    this.model.bind("change", this.render, this);
                    this.model.bind("destroy", this.close, this);
                },

                render: function () {
                    $(this.el).html(this.template(this.model.toJSON()));
                    var context = this.$("#chart_div")[0];
                    var stock = this.model;
                    stock.set("_id", stock.toJSON()["tickerSymbol"]);
                    //stock.fetch({success: function(model, response, options){
                        //stock.set("data", response);
                        // set interactivity to false
                        console.log("-----------3---------");
                        var chart = new TFChart(stock.get("_id"), stock.attributes['data'], context, false, this.$("#chart_div").width(), this.$("#chart_div").height());
                        return this;
                    //}});     
                }
            });

In your for-loop , you use stock = stocks[i] to get each of the stock, then fetch them.

However, as .fetch is async method, when it starts to execute to render a view for stock, you'll notice that the stock is now point to the last item in the stocks, so it just render the last item for many times.

Why this happens? Because the var use function scope, not block scope(In ES6, there's a let can use block scope, but is a little off-topic here), so all of the .fetch 's success callback, when they want to use stock , they all see the same stock , which would be the last assigned value in for-loop, and should be the last item of stocks.

It's a scope issue, and the solution is to wrap the context to a function, so the function's scope will keep the item for you:

render: function () {
    var stocks = this.model.models;
    var len = stocks.length;
    var startPos = (this.options.page - 1) * 8;
    var endPos = Math.min(startPos + 8, len);

    // Move this.el to here, so the this.el's this won't be a problem.
    var thisEl = this.el;
    var fetchStock = function(stock) {
        stock.set("_id", stocks[i].toJSON()["tickerSymbol"]);
        stock.fetch({success: function(model, response, options){
            stock.set("data", response);
            // set interactivity to false
            console.log("-----------2---------");
            $('.thumbnails', thisEl).append(new StockDashboardItemView({model: stock}).render().el);
        }});
    };

    $(this.el).html('<ul class="thumbnails"></ul>');
    for (var i = startPos; i < endPos; i++) {
        console.log("----------1--------");
        fetchStock(stocks[i]);
    }

    $(this.el).append(new Paginator({model: this.model, page: this.options.page}).render().el);

    return this;
}

As you can see, now when we call fetchStock , it's stock will reference to the current stocks[i] , and that won't be affect by the loop after it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM