2011-08-03 15 views
62

मेरे पास एक आरईएसटी जेसन एपीआई है जो एक सूची "लॉगबुक" देता है। कई प्रकार की लॉगबुक हैं जो अलग-अलग लेकिन समान व्यवहार को लागू करती हैं। डाटाबेस परत पर इस के सर्वर साइड कार्यान्वयन एकल टेबल विरासत का एक प्रकार है, इसलिए एक कार्यपंजी के प्रत्येक JSON प्रतिनिधित्व अपने "प्रकार" शामिल हैं:एक बैकबोन.जेएस एकाधिक मॉडल सबक्लास का संग्रह

[ 
    {"type": "ULM", "name": "My uml logbook", ... , specific_uml_logbook_attr: ...}, 
    {"type": "Plane", "name": "My plane logbook", ... , specific_plane_logbook_attr: ...} 
] 

मैं ग्राहक पक्ष पर इस सर्वर मॉडल की नकल करना चाहते हैं

class LogbookCollection extends Backbone.Collection 
    model: Logbook 
    url: "/api/logbooks" 
:

class Logbook extends Backbone.Model 

class UmlLogbook extends Logbook 

class PlaneLogbook extends Logbook 

... 

मेरे Backbone.Collection कि मैं JSON एपीआई क्वेरी करने के लिए उपयोग करें Logbook मॉडल का एक सेट है:, तो मैं एक आधार Logbook वर्ग और कई कार्यपंजी उप श्रेणियां होती हैं

जब मैं लॉगबुक संग्रह प्राप्त करता हूं, तो क्या प्रत्येक Logbook को इसके संबंधित उप वर्ग (JSON "प्रकार" विशेषता के आधार पर) कास्ट करने का कोई तरीका है?

उत्तर

80

वास्तव में वास्तव में है।

जब आप किसी संग्रह पर 'fetch' कहते हैं, तो यह संग्रह में जोड़ने से पहले Backbone.Collection.parse के माध्यम से प्रतिक्रिया को पास करता है।

है के रूप में बस, के माध्यम से प्रतिक्रिया गुजरता है, लेकिन आप इसे ओवरराइड मॉडल की एक सूची वापस करने के लिए कर सकते हैं संग्रह में जोड़े जाने के लिए 'पार्स' के डिफ़ॉल्ट कार्यान्वयन:

class Logbooks extends Backbone.Collection 

    model: Logbook 

    url: 'api/logbooks' 

    parse: (resp, xhr) -> 
    _(resp).map (attrs) -> 
     switch attrs.type 
     when 'UML' then new UmlLogbook attrs 
     when 'Plane' then new PLaneLogbook attrs 

संपादित करें: रुको, idbentley मेरे सामने वहाँ गया एकमात्र अंतर वह 'प्रत्येक' इस्तेमाल किया और मैंने 'मानचित्र' का उपयोग किया। दोनों काम करेंगे, लेकिन अलग-अलग।

'प्रत्येक' का उपयोग प्रभावी ढंग से उस श्रृंखला को तोड़ता है जो 'fetch' कॉल शुरू होता है ('अपरिभाषित' लौटने के बाद - 'रीसेट' (या 'एड') के बाद की कॉल से कुछ भी नहीं होगा) और सभी प्रसंस्करण सही पार्स समारोह में वहाँ।

'मानचित्र' का उपयोग करके मॉडलों की सूची में विशेषताओं की सूची को बदल देता है और इसे पहले से ही गति में श्रृंखला में भेज देता है।

विभिन्न स्ट्रोक।

संपादित करें पर दोबारा: सिर्फ वहाँ भी एक और तरीका यह है है एहसास हुआ:

'मॉडल' एक संग्रह पर विशेषता वहाँ केवल इतना संग्रह जानता है उस में 'जोड़ें' गुण पारित कर दिया है कि कैसे एक नया मॉडल बनाने के लिए , 'बनाएं' या 'रीसेट' करें। इसका फायदा संग्रह अब पता चल जाएगा कि कैसे करने के लिए की तुलना में 'लाने' अन्य कार्यों के लिए 'डाली' कार्यपंजी के अधिकार के उपवर्ग है

class Logbooks extends Backbone.Collection 

    model: (attrs, options) -> 
    switch attrs.type 
     when 'UML' then new UmlLogbook attrs, options 
     when 'Plane' then new PLaneLogbook attrs, options 
     # should probably add an 'else' here so there's a default if, 
     # say, no attrs are provided to a Logbooks.create call 

    url: 'api/logbooks' 

: तो आप की तरह कुछ कर सकता है।

+0

आपके बहुत पूर्ण उत्तर के लिए धन्यवाद! मैं पार्स विधि के अस्तित्व को जानता था, लेकिन मुझे नहीं पता था कि परिणाम सीधे रीसेट विधि पर पारित किया गया था ... स्रोत कोड को बेहतर तरीके से खोदना चाहिए था! Thx फिर – Tricote

+1

'मॉडल' विधि का उपयोग करके आपका संपादन 'पार्स' का उपयोग करने से काफी बेहतर है क्योंकि आप सही तरीके से इंगित करते हैं कि यह 'रीसेट' के लिए काम करता है। इस तरह नए मॉडल 'fetch' के माध्यम से आते हैं या HTML में बूटस्ट्रैप किए जाते हैं, फिर भी यह काम करता है। धन्यवाद! – philoye

+2

मेरा सुझाव है कि आप उस अंतिम भाग को ऊपर ले जाएं ताकि लोग इसे और अधिक देख सकें :) बस एक विचार – corroded

11

हां। आप संग्रह पर parse समारोह ओवरराइड कर सकते हैं (मैं, वाला उपयोग जावास्क्रिप्ट coffeescript के बजाय कर रहा हूँ, क्योंकि यह जो मैं जानता हूँ, लेकिन मानचित्रण आसान होना चाहिए):

LogbookCollection = Backbone.Collection.extend({ 
    model: Logbook, 
    url: "/api/logbooks", 
    parse: function(response){ 
     var self = this; 
     _.each(response, function(logbook){ 
      switch(logbook.type){ 
      case "ULM": 
       self.add(new UmlLogBook(logbook); 
       break; 
      case "Plane": 
       ... 
      } 
     } 
    } 
}); 

आशा इस मदद करता है।

0

शायद यह eval उपयोग करने के लिए बुरा है, लेकिन यह भी बहुत कुछ माणिक शैली रास्ता (coffeescript) है:

parse: (resp)-> 
    _(resp).map (attrs) -> 
     eval("new App.Models.#{attrs.type}(attrs)") 

तो तुम स्विच/मामलों का एक बहुत लिखने की जरूरत नहीं है, प्रकार सिर्फ सेट विशेषता आपके JSON में यह रेल + सीटियर या अन्य बहुमूल्य विरासत समाधान के साथ बहुत अच्छा काम करता है। आप अपने मामलों में उन्हें जोड़ने के बिना नए वंशज जोड़ सकते हैं।

और आप ऐसे स्थानों का उपयोग अन्य स्थानों पर कर सकते हैं जहां आपको अपने मॉडल वर्ग के आधार पर बहुत सारे स्विच/मामले की आवश्यकता है।

+4

आपको वास्तव में यहां eval का उपयोग करने की आवश्यकता नहीं है, नया ऐप। मॉडल [attrs.type] (attrs) ठीक काम करेगा। – Dmitry

+0

@dgutov, धन्यवाद, सुंदर! –

3

रीढ़ 0.9.1 के रूप में, मैं विधि esa-माटि सूयरोनन के पुल अनुरोध में वर्णित का उपयोग शुरू किया: पैच लागू करने के बाद

https://github.com/documentcloud/backbone/pull/1148

, अपने संग्रह कुछ इस तरह होगा:

LogbookCollection = Backbone.Collection.extend({ 

    model: Logbook, 

    createModel: function (attrs, options) { 
     if (attrs.type === "UML") { // i'am assuming ULM was a typo 
      return new UmlLogbook(attrs, options); 
     } else if (attrs.type === "Plane") { 
      return new Plane(attrs, options); 
     } else { 
      return new Logbook(attrs, options); 
      // or throw an error on an unrecognized type 
      // throw new Error("Bad type: " + attrs.type); 
     } 
    } 

}); 

मेरा मानना ​​है जब से तुम एसटीआई (सभी मॉडल अद्वितीय आईडी है)

1

उपयोग कर रहे हैं यह फिटअपने आप काम कर सकते हैं, या आप submodelTypesBackbone-Relational की सुविधा का उपयोग कर सकते हैं।

संबंधित मुद्दे