2013-01-10 18 views
11

Uczę się Szkieletu.Kolekcja kręgosłupa z wieloma modelami?

Chcę utworzyć listę, która może zawierać różne modele o różnych atrybutach.

Na przykład, wyświetlając zawartość folderu, która może obejmować modele typu pliku i modele folderów typów w dowolnej kolejności.

file : { 
    title : "", 
    date : "", 
    type : "", 
    yaddayadda : "" 
} 

folder : { 
    title : "", 
    date : "", 
    haminahamina : "" 
} 

Jaki jest właściwy sposób reprezentowania tego w kręgosłupie? Czy można mieć jedną kolekcję z wieloma modelami?

+0

Duplikat: http://stackoverflow.com/questions/6933524/a-backbone-js-collection-of-multiple-model-subclasses/6934682#6934682 – treecoder

Odpowiedz

21

Tworzenie modelu bazowego, że inne modele dziedziczenia od:

var DataModel = Backbone.Model.extend({ 
    // Whatever you want in here 
}); 

var FileModel = DataModel.extend({ 
    // Whatever you want in here 
}); 

var FolderModel = DataModel.extend({ 
    // Whatever you want in here 
}); 

i sprawiają, że typ kolekcji model być ten sam model Base:

var DataCollection = Backbone.Collection.extend({ 
    model: DataModel 
}); 
+0

Dzięki za odpowiedzi. Kiedy kolekcja DataCollection zostanie przekazana do renderowanego widoku, w jaki sposób renderowałbyś atrybut należący do FileModel lub FolderModel? – user1031947

+1

Zawsze możesz sprawdzić, czy 'obj instanceof FileModel' (lub' FolderModel') i renderować poprawnie. – Lukas

+1

Tak też bym to zrobił, ale jak przechodzisz w DataCollection, o którym mówisz (wywołanie AJAX)? Jeśli tak jest, musisz sprawdzić, czy ta unikalna właściwość istnieje w odpowiedzi (np. Jeśli (someModel.someUniqueProperty) {// wyrenderuje ją w widoku, który obsłuży tę wartość właściwości};). –

16

Można również zrobić to kręgosłup droga. Zapoznaj się z dokumentami: backbone collection Zasadniczo można utworzyć różne modele, dodając atrybut łamacza tie, powiedz "typ" w tym przypadku.

var file = Backbone.Model.extend({ 
     defaults: { 
      // will need to include a tie breaker attribute in both models 
      type: 'file' 
     } 
    }), 
    folder = Backbone.Model.extend({ 
     defaults: { 
      // tie breaker 
      type: 'folder' 
     } 
    }); 

var fs = Backbone.Collection.extend({ 
    model: function(model, options) { 
     switch(model.type) { 
      case 'file': 
       return new file(model, options); 
       break; 
      case 'folder': 
       return new folder(model, options); 
       break; 
     } 
    } 
}); 

// after that just add models to the collection as always 
new fs([ 
    {type: 'file',name: 'file.txt'}, 
    {type: 'folder',name: 'Documents'} 
]); 
+3

Podoba mi się ta metoda, nie tylko jest "kręgosłupem", ale nie wymaga dodatkowej logiki biznesowej @dennis wspomnianej powyżej, w rzeczywistości nigdy nie będziesz potrzebować żadnych obejść, ponieważ wszystko będzie działać tak, jakbyś oczekiwał to do. również, myślę, że miałeś na myśli wiersz do przeczytania: 'var fs = Backbone.Collection.extend ({' –

+0

Jest to bardzo wygodne podejście, dzięki –

+0

Należy pamiętać, że to łamie 'this.model.prototype.idAttribute', dzięki czemu powinieneś rzucić okiem na [odpowiedź] Macieja (http://stackoverflow.com/a/35603643/1218980), który rozwiązuje to za pomocą 'ModelFactory.prototype.idAttribute'. –

1

Szkielet documention nie jest w tym przypadku kompletny. Nie zadziała w przypadku użycia z opcją merge:true i idAttribute. W takim przypadku trzeba:

var ModelFactory = function (attr, options) { 
    switch (attr.type) { 
    case 'file': 
     return new file(attr, options); 
    case 'folder': 
     return new folder(attr, options); 
    } 
}; 
ModelFactory.prototype.idAttribute = '_id'; 

var fs = Backbone.Model.extend({ 
    model: ModelFactory 
}); 
+0

'ModelFactory.prototype.idAttribute' jest tutaj bardzo ważny, ponieważ pozwala uniknąć duplikatów. –

+0

Zastępowanie funkcji' modelId' kolekcji byłoby równoważne. –

-2
 var bannedList = app.request('rest:getBan'); 
     var whiteIpList = app.request("rest:getWhite"); 
     var whiteGroupList = app.request("rest:...."); 
     $.when(bannedList, whiteIpList, whiteGroupList). 
done(function (bannedList, whiteIpList, whiteGroupList) { 
      var collection = new Backbone.Collection(); 
      collection.add(bannedList); 
      collection.add(whiteIpList); 
      collection.add(whiteGroupList); 

     }); 


    app.reqres.setHandler("rest:getBannedList", function (data) { 
     return API.getBannedList(data); 
    }); 
    getBannedList: function (data) { 
       var user = new Backbone.Model(); 
       user.url = '/banned'; 
       user.cid = 'bannedList'; 
       var defer = $.Deferred(); 

       user.fetch({ 
        type: 'GET', 
        data: data, 
        success: function (data) { 
         defer.resolve(data); 
        }, 
        error: function (data) { 
         defer.reject(data); 
        } 
       }); 
       return defer.promise(); 
      }, 
Powiązane problemy