简体   繁体   中英

Backbone: Collection nested in a model

I will list some code and explain the situation.
(1) I instantiate the App.views.tasks . In the initialize function of this view, I fetch the tasks.
(2) From the render function, I instantiate a App.views.task for each task.
(3) In the initialize function of App.views.task , I instantiate an App.views.comments and I pass to it the collection of comments and the reference to the DOM element, where the task is rendered.
(4) App.views.comments kicks the fetching of the comments of the task.

Question :
The reference to the DOM element that I pass to the App.views.comments would be undefined if there wasn't the delay induced by the fetching of the comments.
If I passed the reference el in the render function, everything would be fine, but that also means that App.views.comments is instantiated every time render is called, which is not fine. So this is only a lucky way to do it, it only gets the chance to have it defined because there is a fetching , otherwise it would be undefined .
I added some comments that explain in place what happens, you can find them in App.views.task and App.views.comments .

What is the best way to solve this possible in some cases issue?

App.collections.Tasks = Backbone.Collection.extend({
        model: App.models.Task,
        url: App.baseHrefReq + '/tasks/all'
});
App.models.Task = Backbone.Model.extend({
initialize: function() {
            this.set({comments: new App.collections.taskComments});
            this.get('comments').url = App.baseHrefReq + '/comments/get/task-id/' + this.get('id');
        }
});
App.views.tasks = Backbone.View.extend({
        initialize: function() {
            App.iCollections.Tasks = new App.collections.Tasks;

            App.iCollections.Tasks.bind('reset', this.render, this);
            App.iCollections.Tasks.bind('add', this.renderTask, this);

            App.iCollections.Tasks.fetch();
        },
        render: function() {
            $('.feed-list').html('');
            App.iCollections.Tasks.each(this.renderTask);

        },
        renderTask: function(task) {
            var view = new App.views.task({model: task});
            $('.feed-list').append(view.render().el);
        }
    }); 
    App.iViews.tasks = new App.views.tasks;

App.views.task = Backbone.View.extend({
        tagName: 'li',
        template: _.template($('#task-item-template').html()),
        initialize: function() {
            this.model.bind('change', this.render, this);
            this.model.bind('destroy', this.remove, this);
            this.model.get('comments').bind('reset', this.render, this);
            this.model.get('comments').bind('add', this.render, this);
            this.model.get('comments').bind('remove', this.render, this);
            //I pass the DOM reference here
            this.commentsView = new App.views.comments({collection: this.model.get('comments'), el: this.$el}); 
        },
        render: function() {
            var modelJSON = this.model.toJSON();
            //the DOM reference is only ready and defined here
            this.$el.html(this.template(modelJSON)); 


            return this;
        }
});
App.views.comments = Backbone.View.extend({
        initialize: function() {
            _.bindAll(this, 'render', 'renderComment');

            this.collection.bind('reset', this.render, this);
            this.collection.bind('add', this.renderComment, this);
            this.collection.bind('remove', this.remove, this);

            this.collection.fetch();

        },
        render: function() {
            //if there wasn't the fetch() above, $el would be undefined at this point
            this.$el.find('.feed-comments ul').html('');
            this.collection.each(this.renderComment);

        },
        renderComment: function(comment) {
            var view = new App.views.comment({model: comment});
            this.$el.find('.feed-comments ul').append(view.render().el);
        }
    });
});
App.views.comment = Backbone.View.extend({...})

I suggest you to move this line this.commentsView = new App.views.comments({collection: this.model.get('comments'), el: this.$el}); to the end of the App.views.task.render() .

In fact this line is part of a rendering behavior so this is better place for it.

Doing this you also con do it this way:

this.commentsView = new App.views.comments({collection: this.model.get('comments'), el: this.$el.find('.feed-comments ul')});

What I think it is asking for.

You should do more things like call this.commentsView.render() also in the App.views.task.render() but I think you can follow me from here.

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