2012-02-09 31 views
6

我正在嘗試製作一個小的backbone.js應用程序,但與事物的順序發生衝突。backbone.js視圖在模型提取之前呈現

在我的html文件,我在包頭中的兩個腳本塊:

<script type="text/template" id="model-template"> 
    <a href="#"><%= title %></a> 
</script> 

<script type="text/javascript"> 
    jQuery(function(){ 
    window.model.fetch(); 
    }); 
</script> 

在我app.js,我已經定義了一個簡單的模型,視圖和路由器。

(function($) { 

window.MyModel = Backbone.Model.extend({ 
    url: '/mymodel' 
}); 

window.mymodel = new MyModel(); 

$(document).ready(function() { 

    window.MyModelView = Backbone.View.extend({ 
     template: _.template($('#mymodel-template').html()), 

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

     render: function() { 
      var renderedContent = this.template(this.model.toJSON()); 
      $(this.el).html(renderedContent); 
      return this; 
     } 
    }); 
}); 

window.MyApp = Backbone.Router.extend({ 
    routes: { 
     '': 'home' 
    }, 

    initialize: function() { 
     this.myModelView = new MyModelView({ 
      model: window.mymodel 
     }); 
    }, 

    home: function() { 
     var $body = $('body'); 
     $body.empty(); 
     $body.append(this.myModelView.render().el); 
    } 
}); 

$(function() { 
    window.App = new MyApp(); 
    Backbone.history.start({pushState: true}); 
}); 

})(jQuery); 

該應用程序由一個簡單的sinatra應用程序提供服務。該URL /mymodel供應靜態JSON文件:

{ 
    "title": "My Model", 
} 

當加載應用程序,我得到在JavaScript控制檯中的錯誤:

Uncaught ReferenceError: title is not defined 

這個問題似乎是,該視圖前呈現自己該模型從服務器獲取。這是爲什麼?

昨天,我跟蹤了PeepCode的前兩個backbone.js截屏視頻。我試圖將我的應用程序與屏幕錄像中的應用程序進行比較,但無法看到爲什麼我的應用程序想要工作的原因。

有什麼建議嗎?

+0

花了我幾個小時......小時才發現,這就是爲什麼我的應用程序不工作,工作了一些時間而不是其他工作,或者在某些瀏覽器而不是其他工作。當我想到如何獲取應該工作的一種菜鳥錯誤。學過的知識。 我覺得太多的骨幹例子使用硬編碼的數據和非常重要的概念,就像今年秋天一樣。 – IcedDante 2014-11-29 06:14:45

回答

16

在這種情況下,您應該引導模型數據,以便在頁面加載時可用。

而不是

window.model.fetch(); 

把像這樣的(如果使用.erb)

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

否則,你需要渲染視圖一旦模型被取出例如

綁定視圖來呈現在型號改變

initialize: function() { 
    _.bindAll(this, 'render'); 

    this.model.on("change", this.render); 
}, 

或處理模型的成功。從以前的答案提取和渲染視圖

window.model.fetch({ 
    success: function (model, response) { 
     window.MyApp.myModelView.render(); 
    } 
}); 
+0

這個答案讓我最接近解決方案。我刪除了在我的路由器中呈現的調用,但保留了將視圖'el'屬性添加到文檔的代碼。因此,當獲取完成時,它會更改我的模型,該模型引發更改事件,該事件調用render方法。 – Vegar 2012-02-13 20:28:22

1

從服務器重置模型的狀態。如果該模型有 從未填充過數據,或者如果您想確保您的 具有最新的服務器狀態,則此功能很有用。如果 服務器的狀態與當前屬性不同,將會觸發「更改」事件。在選項散列中接受 成功和錯誤回調,這些回調通過 (模型,響應)作爲參數傳遞。

在這種情況下,您需要在成功回調中呈現視圖。

model.fetch({ 
    error: function() { 
    }, 
    success: function (model, response) { // model is ready now 
     // do view stuff here 
    } 
}); 
1

顯然,你知道你需要渲染上獲取成功的回調,但是我覺得你的問題比多一點。也就是說,您的主路線用於立即構建myModelView,而不是在數據加載時。發生這種情況是因爲您正在調用render()以追加到body。相反,嘗試使用現有元素初始化視圖。這樣可以延遲呼籲渲染,直到取完成:

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 
     }); 
    } 
}); 

現在,你已經不叫渲染()還沒有,但你的觀點是成功地連接到DOM,你打算。

+0

所以在這裏,你是在初始化和home函數中創建一個MyModelView的實例?或者我應該從初始化中刪除它? – Vegar 2012-02-10 20:09:50

+0

你是對的,將它從​​初始化中移除。對困惑感到抱歉。無論如何,將它放入初始化並不總是有意義的,因爲通常您將根據調用的路由方法呈現不同的視圖。 – 2012-02-10 20:28:04

5

您還可以利用遞延對象的http://api.jquery.com/category/deferred-object/Backbone.Model.fetch()的回報,這樣的:

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; 
     } 
    } 
}); 

您可能希望創建一個存儲你的模型延期對象骨幹模型的擴展,你可以引用,就像這樣:

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

然後在您的視圖渲染方法,你可以這樣說:

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; 
     } 
    }  

使用擴展模型並在整個主幹應用中遵循此模式可能非常方便。

相關問題