简体   繁体   English

Backbone.js将模型添加到集合问题

[英]Backbone.js Adding Model to Collection Issue

I am building a test application in Backbone.js (my first app using Backbone). 我正在Backbone.js(我的第一个使用Backbone的应用程序)中构建测试应用程序。 The app goes like this: 该应用程序是这样的:

  1. Load Data from server "Plans" 从服务器“计划”加载数据
  2. Build list of plans and show to screen 构建计划列表并显示到屏幕
  3. There is a button to add a new plan 有一个按钮可以添加新计划
  4. Once new plan is added, add to collection ( do not save to server as of now ) 添加新计划后,添加到集合(不要保存到服务器)
  5. redirect to index page and show the new collection ( includes the plan you just added) 重定向到索引页面并显示新集合(包括刚刚添加的计划)

My issue is with item 5. When I save a plan, I add the model to the collection then redirect to the initial view. 我的问题是第5项。当我保存计划时,我将模型添加到集合中,然后重定向到初始视图。 At this point, I fetch data from the server. 此时,我从服务器获取数据。 When I fetch data from the server, this overwrites my collection and my added model is gone. 当我从服务器获取数据时,这会覆盖我的集合,我添加的模型就消失了。

How can I prevent this from happening? 我怎样才能防止这种情况发生? I have found a way to do this but it is definitely not the correct way at all. 我找到了一种方法来做到这一点,但它绝对不是正确的方法。 Below you will find my code examples for this. 您将在下面找到我的代码示例。 Thanks for the help. 谢谢您的帮助。

PlansListView View: PlansListView查看:

var PlansListView = Backbone.View.extend({

    tagName : 'ul',

    initialize : function()
    {
        _.bindAll( this, 'render', 'close' );
        //reset the view if the collection is reset 
        this.collection.bind( 'reset', this.render , this );

    },
    render : function()
    {
        _.each( this.collection.models, function( plan ){

            $( this.el ).append( new PlansListItemView({ model: plan }).render().el );

        }, this );

        return this;
    },
    close : function()
    {
        $( this.el ).unbind();
        $( this.el ).remove();  

    }   
});//end

NewPlanView Save Method NewPlanView保存方法

var NewPlanView = Backbone.View.extend({

    tagName : 'section',
    template : _.template( $( '#plan-form-template' ).html() ),
    events : {
        'click button.save' : 'savePlan',
        'click button.cancel' : 'cancel'

    },
    intialize: function()
    {
        _.bindAll( this, 'render', 'save', 'cancel' );  

    },
    render : function()
    {
        $( '#container' ).append( $( this.el ).html(this.template( this.model.toJSON() )) );                                    
        return this;
    },
    savePlan : function( event )
    {

        this.model.set({

            name : 'bad plan',
            date : 'friday',
            desc : 'blah',
            id : Math.floor(Math.random()*11),
            total_stops : '2'           
        });

        this.collection.add( this.model );

        app.navigate('', true );
        event.preventDefault();

    },
    cancel : function(){}
});

Router (default method): 路由器(默认方法):

    index : function()
    {
        this.container.empty();
        var self = this;

        //This is a hack to get this to work
        //on default page load fetch all plans from the server
        //if the page has loaded ( this.plans is defined) set the updated plans collection to the view
        //There has to be a better way!!
        if( ! this.plans )
        {
            this.plans = new Plans();


            this.plans.fetch({

                success: function()
                {
                    self.plansListView = new PlansListView({ collection : self.plans });
                    $( '#container' ).append( self.plansListView.render().el );
                    if( self.requestedID ) self.planDetails( self.requestedID );
                }   
            });
        }
        else
        {
            this.plansListView = new PlansListView({ collection : this.plans });
            $( '#container' ).append( self.plansListView.render().el );
            if( this.requestedID ) self.planDetails( this.requestedID );

        }
    },

New Plan Route: 新计划路线:

    newPlan : function()
    {   var plan = new Plan({name: 'Cool Plan', date: 'Monday', desc: 'This is a great app'});
        this.newPlan = new NewPlanView({ model : plan, collection: this.plans });
        this.newPlan.render();
    }   

FULL CODE ( function( $ ){ 完整代码(函数($){

var Plan = Backbone.Model.extend({

    defaults: {
        name : '',
        date : '',
        desc : ''   
    }   
});

var Plans = Backbone.Collection.extend({

    model : Plan,
    url : '/data/'  

});     






$( document ).ready(function( e ){

    var PlansListView = Backbone.View.extend({

        tagName : 'ul',

        initialize : function()
        {
            _.bindAll( this, 'render', 'close' );
            //reset the view if the collection is reset 
            this.collection.bind( 'reset', this.render , this );

        },
        render : function()
        {
            _.each( this.collection.models, function( plan ){

                $( this.el ).append( new PlansListItemView({ model: plan }).render().el );

            }, this );

            return this;
        },
        close : function()
        {
            $( this.el ).unbind();
            $( this.el ).remove();  

        }   
    });//end

    var PlansListItemView = Backbone.View.extend({

        tagName : 'li',
        template : _.template( $( '#list-item-template' ).html() ),
        events :{

            'click a' : 'listInfo'  
        },
        render : function()
        {
            $( this.el ).html( this.template( this.model.toJSON() ) );
            return this;            
        },
        listInfo : function( event )
        {


        }

    });//end


    var PlanView = Backbone.View.extend({

        tagName : 'section',
        events : {
            'click button.add-plan' : 'newPlan'
        },
        template: _.template( $( '#plan-template' ).html() ),
        initialize: function()
        {
            _.bindAll( this, 'render', 'close', 'newPlan' );            
        },
        render : function()
        {
            $( '#container' ).append( $( this.el ).html( this.template( this.model.toJSON() ) ) );
            return this;
        },
        newPlan : function( event )
        {
            app.navigate( 'newplan', true );
        },
        close : function()
        {
            $( this.el ).unbind();
            $( this.el ).remove();  
        }   

    });//end


    var NewPlanView = Backbone.View.extend({

        tagName : 'section',
        template : _.template( $( '#plan-form-template' ).html() ),
        events : {
            'click button.save' : 'savePlan',
            'click button.cancel' : 'cancel'

        },
        intialize: function()
        {
            _.bindAll( this, 'render', 'save', 'cancel' );  

        },
        render : function()
        {
            $( '#container' ).append( $( this.el ).html(this.template( this.model.toJSON() )) );                                    
            return this;
        },
        savePlan : function( event )
        {

            this.model.set({

                name : 'bad plan',
                date : 'friday',
                desc : 'blah',
                id : Math.floor(Math.random()*11),
                total_stops : '2'           
            });

            this.collection.add( this.model );

            app.navigate('', true );
            event.preventDefault();

        },
        cancel : function(){}
    });



    var AppRouter = Backbone.Router.extend({

        container : $( '#container' ),

        routes : {

            ''              : 'index',
            'viewplan/:id'  : 'planDetails',
            'newplan'           : 'newPlan'
        },
        initialize: function(){

        },
        index : function()
        {
            this.container.empty();
            var self = this;

            //This is a hack to get this to work
            //on default page load fetch all plans from the server
            //if the page has loaded ( this.plans is defined) set the updated plans collection to the view
            //There has to be a better way!!
            if( ! this.plans )
            {
                this.plans = new Plans();


                this.plans.fetch({

                    success: function()
                    {
                        self.plansListView = new PlansListView({ collection : self.plans });
                        $( '#container' ).append( self.plansListView.render().el );
                        if( self.requestedID ) self.planDetails( self.requestedID );
                    }   
                });
            }
            else
            {
                this.plansListView = new PlansListView({ collection : this.plans });
                $( '#container' ).append( self.plansListView.render().el );
                if( this.requestedID ) self.planDetails( this.requestedID );

            }
        },

        planDetails : function( id )
        {

            if( this.plans )
            {
                this.plansListView.close();
                this.plan = this.plans.get( id );

                if( this.planView ) this.planView.close();
                    this.planView = new PlanView({ model : this.plan });
                this.planView.render();
            }
            else{

                this.requestedID = id;
                this.index();
            }

            if( ! this.plans ) this.index();
        },

        newPlan : function()
        {   var plan = new Plan({name: 'Cool Plan', date: 'Monday', desc: 'This is a great app'});
            this.newPlan = new NewPlanView({ model : plan, collection: this.plans });
            this.newPlan.render();
        }   
    });



    var app = new AppRouter();
    Backbone.history.start();

}); 








})( jQuery );

Are you fetching the data every time you hit the index page because you want the list to be in sync with the database (ie someone else added an item and you want it reflected)? 您是否每次进入索引页面时都要获取数据,因为您希望列表与数据库同步(即其他人添加了一个项目并且您希望它反映出来)?

If that is not the case, what you are doing seems fine to me; 如果情况并非如此,那么你所做的对我来说似乎不错; you are only fetching when the data does not exist. 您只在数据不存在时获取。

If you, however, do want the list to be in sync; 但是,如果您确实希望列表同步; but you still wish to have your newly added items rendered among them; 但是你仍然希望在他们中间添加新添加的项目; you can either merge from the fetched list or use another list to hold the newly added data. 您可以从提取的列表中合并,也可以使用其他列表来保存新添加的数据。

If you use another list, you just have to render both list; 如果你使用另一个列表,你只需要渲染两个列表; the unsaved list should probably exist either at the top or the bottom of the persisted list, grouped together. 未保存的列表应该存在于持久列表的顶部或底部,组合在一起。

I think you are looking for the "remove" parameter, it will prevent models being removed from the collection during a fetch. 我认为您正在寻找“删除”参数,它将阻止在获取期间从集合中删除模型。

this.plans.fetch({remove: false})

See the backbone documentation for further details about the fetch method. 有关fetch方法的更多详细信息,请参阅主干文档

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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