backbone.js view renders before model fetch

前端 未结 5 978
自闭症患者
自闭症患者 2021-01-05 15:51

I\'m trying to make a small backbone.js app, but struggle with the order of things.

In my html file, I have two script blocks in the header:



        
相关标签:
5条回答
  • 2021-01-05 16:09

    Resets the model's state from the server. Useful if the model has never been populated with data, or if you'd like to ensure that you have the latest server state. A "change" event will be triggered if the server's state differs from the current attributes. Accepts success and error callbacks in the options hash, which are passed (model, response) as arguments.

    In this case, you'll want to render the view in the success callback.

    model.fetch({
       error: function () {
       },
       success: function (model, response) { // model is ready now
          // do view stuff here
       }
    });
    
    0 讨论(0)
  • 2021-01-05 16:15

    You can always set-up a default title using the 'defaults' option: http://documentcloud.github.com/backbone/#Model-defaults.

    0 讨论(0)
  • 2021-01-05 16:18

    In this case you should bootstrap your model data so that it's available on page load.

    Instead of

    window.model.fetch();
    

    put something like this in (if using a .erb)

    <script>
        window.model = new MyModel(<%= @model.to_json %>);
    </script>
    

    Otherwise you need to render the view once the model is fetched e.g.

    bind the view to render when the model changes

    initialize: function () {
        _.bindAll(this, 'render');
    
        this.model.on("change", this.render);
    },
    

    or handle the success of the model.fetch and render the view

    window.model.fetch({
       success: function (model, response) { 
          window.MyApp.myModelView.render();
       }
    });
    
    0 讨论(0)
  • 2021-01-05 16:21

    You can also take advantage of the deferred object http://api.jquery.com/category/deferred-object/ that Backbone.Model.fetch() returns, like this:

    window.MyModel = Backbone.Model.extend({
       url: '/mymodel'
    });
    
    //when the model is fetched, store a reference to the jQuery deferred object
    window.MyModelFetch = window.MyModel.fetch();
    
    window.MyModelView = Backbone.View.extend({
        template: _.template($('#mymodel-template').html()), 
    
        initialize: function () {
            _.bindAll(this, 'render');
        },
    
        render: function () {
            //reference the deferred object and use 'done' method 
            //to register a callback after complete
            window.MyModelFetch.done(function(){
                 var renderedContent = this.template(this.model.toJSON());
                 $(this.el).html(renderedContent);
                 return this;
            }
        }
    });
    

    You may want to create an extension of the backbone model that stores a deferred object on your model that you can reference, like this:

     Backbone.DeferrableModel = Backbone.Model.extend({
          fetch: function(){
               this.fetching = Backbone.Model.prototype.fetch.apply(this, arguments);
               return this.fetching;
          }
     });
    

    Then in your view render method, you can just say this:

      render: function () {
            //the deferred reference is now directly referenced from your model
            this.model.fetching.done(function(){
                 var renderedContent = this.template(this.model.toJSON());
                 $(this.el).html(renderedContent);
                 return this;
            }
        }    
    

    It can be very handy to use an extended model and follow this pattern throughout your backbone application.

    0 讨论(0)
  • 2021-01-05 16:23

    Clearly from the previous answers, you know that you need to render on the fetch success callback, however I think you problem is a bit more than that. Namely, your home route is used to build myModelView immediately rather than when its data loads. This is happening because you are calling render() in order to append to body. Instead, try and initialize the view with an existing element. This way you can delay the call for render until fetch has completed:

    window.MyApp = Backbone.Router.extend({
        routes: {
            '': 'home'
        },
    
        initialize: function () {
    
        },
    
        home: function() {
            var $body = $(document.body).empty();
            var myModelEl = $("<div></div>").appendTo($body);
    
            this.myModelView = new MyModelView({
                model: window.mymodel,
                el: myModelEl
            });
        }
     });
    

    Now, you haven't called render() yet, but your view is successfully attached to the DOM as you intended.

    0 讨论(0)
提交回复
热议问题