10

我的web應用程序有一個複合結構,即每個類別集合可以包含單個項目和其他類別的混合作爲其行/節點/子項(此處不確定正確的術語)。實際上,它比這更簡單一些,因爲每個集合都由一個模型Category來表示,所以基本上每個Category集合都具有Item模型和Category模型作爲子模型。使用MVC/Backbone.js實現複合模式

一般來說,這是使用MVC實現這種結構的一種可取的方式嗎?更具體地說,在Backbone.js中,一個集合有可能擁有一個模型工廠(取決於json並根據json的結構計算生成哪個模型)而不是靜態模型屬性?

+0

總之,我會說,「我不明白爲什麼不」,但我很好奇別人會說什麼。 – JayC 2012-01-19 19:17:21

回答

1

是的,你可以。我以前做過。我覺得這個鏈接可以幫助你:http://documentcloud.github.com/backbone/#Collection-model

下面是我用我的項目的主腳本之一:https://gist.github.com/b65893e0c2e3c46d3dc1

+0

我真的無法弄清楚你在那個要點上做了什麼。我只能看到一種類型的模型,TransactionDetail被添加到集合中,我希望自由添加兩種類型。自從發佈這個問題以來,我開始編輯Backbone以嘗試獲取我需要的內容,但是它爲內存集合提供了內置的唯一ID規則,所以我認爲我需要使用model type和id生成的id創建一些橋接模型。但我仍然有興趣看看有沒有更好的方法 – wheresrhys 2012-01-19 20:21:41

+0

我明白了。那麼,我希望你能找到像你需要的方式去做。最好的運氣。 – MauroPorrasP 2012-01-20 03:00:23

+0

他是對的,你可以給出一個工廠函數作爲你的集合類的模型屬性... http://documentcloud.github.com/backbone/#Collection-model – inf3rno 2013-04-23 21:41:42

5

我假設你接收JSON類別/項目列表,看起來像這...

{ 
    'id': 1, 
    'name': 'My 1st Category', 
    'children': [ 
     { 
      'id': 2, 
      'name': 'My 2nd Category', 
      'children': [] 
     }, 
     { 
      'id': 1, 
      'name': 'An Item', 
      'price': 109.99 
     } 
    ] 
} 

Backbone.js的沒有任何關係了,它支持一個集合多種型號的方塊,但它也不會對你把一個集合中的類型的模型任何限制。

在集合定義中指定模型類型只做一件事,它讓Backbone知道如果將原始JSON傳遞給集合而不是Backbone.Model對象時要創建的模型類型。如果您將Item模型添加到已包含幾個Category模型的集合中,Backbone將不會將其彈出到模型列表中;它不做任何類型檢查。因此,考慮到這一點,除了傳遞原始JSON之外,您幾乎可以使用集合提供的所有內容;你需要自己處理。所以你的選擇是事先建立你的模型,使它們成爲Backbone.Model對象,或者創建一些可以爲你解析的東西。

對於第二個選項,解析器,我建議將一個特殊的變量傳遞給包含原始JSON的集合,然後在你的initialize函數中處理它。這裏有一個例子:

var CategoryCollection = Backbone.Collection.extend({ 
    initialize: function(m, models) { 
     _.each(models, function(model) { 
      var modelObject = null; 
      if (model.price !== undefined) { 
       modelObject = new Item(model); 
      } else { 
       modelObject = new Category(model); 
      } 

      this.add(modelObject); 
     }, this); 
    } 
}); 

所以這是一個有點哈克,但你確定模型的基礎上,類型,如果有(在我的例子price)的特定字段,創建模型對象,然後添加到採集。

你會然後調用它是這樣的:你有

var myCollection = new CategoryCollection([], myJSON); 

通知傳遞一個空數組作爲第一個參數,因爲這就是你怎麼正常通過一組模型到集合中。

使用集合時上以後,就可以判斷,如果你有ItemCategory處理使用簡單instanceof檢查:

_.each(myCollection.models, function(model) { 
    if (model instanceof Item) { 
     console.log("It's an Item! Price: ", model.get("price")); 
    } else { 
     console.log("It's a Category!"); 
    } 
}); 
+0

整潔的想法,使用選項參數走私生數據。 – wheresrhys 2012-01-20 16:59:30

+0

哈哈謝謝。我認爲這比黑客攻擊Backbone.js源代碼更容易。我想要清理它,你總是可以創建一個包裝類,只傳遞你的JSON,然後創建並返回你的集合。 – 2012-01-20 17:10:49

+0

是的,我想劫持/包裝一些其他收集方法,主要是因爲內部Backbone.Model期望id是唯一的,例如我需要適應id,因此它或者接受一個鍵值對{modelType:id} ,或者減少到格式化的字符串。 – wheresrhys 2012-01-20 19:42:12

1

這是相當簡單的通過覆蓋內置的公共方法parse取得toJSON在檢索和保存模型數據時由主幹在內部使用。

首先,當您從數據庫中檢索模型時,您應該覆蓋模型的parse方法,以創建表示示例中給定項目的模型。

然後保存toJSON方法用於將數據序列化回服務器可以理解的內容 - 您只需在每個項目的Model上調用toJSON方法即可將其序列化爲後端將識別的格式。如果您查看Backbone.sync的代碼,您將看到如果沒有傳遞自定義數據,則模型總是使用toJSON進行序列化。

讓我知道你是否需要更詳細的信息,但我相信你應該能夠從這裏撿起它!

+0

我認爲這可能構成解決方案的一部分,但也有其他方法可能需要調整,例如Backbone.Collection._prepareModel(對於我的應用程序,我可以確保我永遠不會將原始json傳遞給Collection.add(調用。 prepareModel內部),但它會很高興有一個解決方案,可以處理使用Collection.add爲jsons數組 – wheresrhys 2012-01-26 10:13:01

+0

我相信覆蓋模型的'set'方法來解析屬性/通過JSON可以做詭計 - 它被稱爲當使用'new Model({...})'和使用'collection.add([{...},...])'' – 2012-01-26 13:52:00

+1

ps時,初始化模型以設置傳遞的屬性默認情況下會擴展。儘管骨幹0.9的快速接近發佈,我們已經學會了艱難的方式,修改私有API方法可能會對你產生適得其反的作用:)這就是爲什麼我試圖遠離搞亂_prepareModel它不應該消失的原因 - 但是例如'_add'和'_remove'現在已經在主幹 – 2012-01-26 13:54:20

1

是的,您可以使用工廠方法模式在骨幹的集合中創建模型。假設在@kpeel's answer建議的數據結構,你可以定義

// Factory method 
var CategoryOrItemFactory = function(data, options) { 
    if (data.children) { 
     return new Category(data, options); 
    } else { 
     return new Item(data, options); 
    } 
}; 

// Model definitions 
var Item = Backbone.Model.extend(); 

var Category = Backbone.Model.extend({ 
    initialize: function() { 
     this.children = new Children(this.get("children")); 
    } 
}); 

var Children = Backbone.Collection.extend({ 
    model: CategoryOrItemFactory 
}); 

然後,您可以創建你的根項目(類別),並已經創建了完整的數據結構:

// create the root item 
var rootItem = new Category(rawData); 

訪問類別的兒童及其children財產,例如

rootItem.children.get(2).get("name"); 

這裏是一個jsFiddle with the above code玩。

+0

的主分支中消失了。但是仍然存在與數據庫同步和Backbone.Collection對獨特id的期望(例如,get無法正常工作http: //jsfiddle.net/Z7Dbr/ - 它返回第二個匹配結果並忽略第一個)。我注意到在你的例子中,Category擴展了模型而不是Collection,我也不確定我對此有多舒服,儘管爲了避免對backbone.js進行廣泛的重構,也許我必須創建一些混合類作爲一個財產集合,而不是從集合繼承 – wheresrhys 2012-01-26 11:34:32

+0

好吧,我試圖回答你的問題:是否有可能建立模型工廠(是)。您的類別必須具有屬性(例如ID),因此它們需要從模型派生(例如,集合的「get」完成與模型的方法不同的其他功能)。關於ID:首先如何識別數據條目?我想應該可以很容易地創建一個有意義和唯一的標識符? – 2012-01-26 13:49:19

+0

至於同步:應該可以爲Items/Categories和Children設置正確的url值。你如何同步你的數據?你能告訴我們一些真實的數據嗎? – 2012-01-26 13:57:29