Napisałem kilka odpowiedzi dotyczących używania parse()
i set()
do tworzenia instancji i wypełniania pod-modeli i sub-kolekcji (danych zagnieżdżonych). Jednak nie widziałem naprawdę wyczerpującej odpowiedzi, która konsoliduje niektóre z wielu praktyk, które widziałem. Mam tendencję do wędrowania trochę, kiedy piszę dużo, więc mogę trochę odejść, ale może to być przydatne dla osób przechodzących przez podobne problemy.
Istnieje kilka sposobów, aby to zrobić. Używanie parse()
jest jednym z nich. Manipulowanie set()
jest kolejnym. Tworzenie ich w twoim initialize()
jest kolejnym. Robiąc to wszystko poza modelem ścieżki, jest inny (na przykład path = new Path(); path.nodes = new NodeCollection();
itp.)
Drugą kwestią jest to. Czy chcesz, aby węzły i kolekcje krawędzi były atrybutami modelu? Lub właściwości modelu?
Och tak wielu wyborów. Dużo swobody, ale czasami (ku naszej frustracji) utrudnia określenie "właściwej drogi".
Ponieważ pojawia się to często, mam zamiar zrobić długi post i przejść przez te jeden po drugim. Więc weź mnie ze sobą, kiedy będę aktualizować tę odpowiedź.
Robi to poza modelami - proste i prosto do przodu
Zazwyczaj jest to łatwy sposób, aby dodać zagnieżdżone modele i kolekcje, kiedy tylko jest to potrzebne w konkretnym modelu lub kolekcji.
path = new PathModel();
path.nodes = new NodeCollection();
path.edge = new EdgeCollection();
// Continue to set up the nested data URL, etc.
Jest to najprostszy sposób i działa dobrze, gdy masz do czynienia z jednym modeli czasowych i zbiorów, które nie muszą mieć definicji. Chociaż można łatwo tworzyć te modele w pewnej metodzie (na przykład metodzie widoku), która tworzy ten obiekt, zanim cokolwiek z nim zrobi.
Korzystanie initialize()
Sub model/kolekcje w każdym modelu
Jeśli wiesz, że każdy przypadek pewnego modelu będą zawsze mieć pod-modelu lub sub-kolekcji, najprostszym sposobem, aby ustawić rzeczy byłoby korzystać z funkcji initialize()
.
Na przykład, weźmy model Path:
Path = Backbone.Model.extend({
initialize: function() {
this.nodes = new NodeCollection();
this.paths = new PathCollection();
// Maybe assign a proper url in relation to this Path model
// You might even set up a change:id listener to set the url when this
// model gets an id, assuming it doesn't have one at start.
this.nodes.url = this.id ? 'path/' + this.id + '/nodes' : undefined;
this.paths.url = this.id ? 'path/' + this.id + '/paths' : undefined;
}
});
Teraz sub-kolekcje mogą być pobierane jak path.nodes.fetch()
i skieruje do odpowiedniego adresu URL. Bułka z masłem.
Korzystanie parse()
dla instancji i ustawienie subdanych
Być może, robi się trochę bardziej skomplikowane, jeśli nie chcą przyjąć każdy model będzie mieć węzły i kolekcje krawędzi. Może chcesz zagnieżdżone modele/kolekcje tylko wtedy, gdy fetch()
odsyła takie dane. Jest tak w przypadku, gdy przydaje się używanie parse()
.
Rzecz z parse()
polega na tym, że pobiera JAKĄKOLWIEK odpowiedź serwera json i może poprawnie nazwać przestrzeń i poradzić sobie z nią przed przekazaniem jej do funkcji modelu set()
. Możemy więc sprawdzić, czy zawiera on dane modelu lub danych nieprzetworzonych kolekcji, i poradzić sobie z nimi przed zmniejszeniem odpowiedzi do atrybutów modelu nadrzędnego.
Na przykład, może z naszego serwera mamy tej odpowiedzi:
// Path model JSON example with nested collections JSON arrays
{
'name':'orange site',
'url':'orange.com',
'nodes':[
{'id':'1', 'nodeColor':'red'},
{'id':'2', 'nodeColor':'white'},
{'id':'3', 'nodeColor':'blue'}
],
'edge':[
{'id':'1', 'location':'north'},
{'id':'1', 'location':'south'},
{'id':'1', 'location':'east'}
]
}
z domyślnym parse()
Backbone to będzie pożerać się i przypisać swoją ścieżkę modelu atrybutów węzły "oraz„krawędzi”z tablicy() danych (nie kolekcje). Dlatego chcemy się upewnić, że nasz parse()
zajmuje się tym właściwie.
parse: function(response) {
// Check if response includes some nested collection data... our case 'nodes'
if (_.has(response, 'nodes')){
// Check if this model has a property called nodes
if (!_.has(this, 'nodes')) { // It does not...
// So instantiate a collection and pass in raw data
this.nodes = new NodeCollection(response.nodes);
} else {
// It does, so just reset the collection
this.nodes.reset(response.nodes);
}
// Assuming the fetch gets this model id
this.nodes.url = 'path/' + response.id + '/nodes'; // Set model relative URL
// Delete the nodes so it doesn't clutter our model attributes
delete response.nodes;
}
// Same for edge...
return response;
}
Można również używać własnego set()
radzić sobie ze swoimi cząstkowych danych. Po długich zwrotach między tymi operacjami lepiej jest manipulować set()
lub robić to w parse()
. Postanowiłem, że jeszcze bardziej lubię używać parse()
. Ale jestem otwarty na myśli innych ludzi na ten temat.
Korzystanie set()
radzić sobie ze swoimi subdanych
Podczas parse()
opiera się albo pobierania danych lub przekazywania danych do kolekcji z opcją parse:true
niektórzy ludzie uważają, że preferencyjna aby zmienić funkcję set()
. Ponownie, nie jestem pewien, czy istnieje właściwy wybór, ale oto jak to zadziała.
set: function(attributes, options) {
// If we pass in nodes collection JSON array and this model has a nodes attribute
// Assume we already set it as a collection
if (_.has(attributes, 'nodes') && this.get("nodes")) {
this.get('nodes').reset(attributes.nodes);
delete attributes.nodes;
} else if (_.has(attributes, 'nodes') && !this.get('nodes')) {
this.set('nodes', new NodeCollection(attributes.nodes));
delete attributes.nodes;
}
return Backbone.Model.prototype.set.call(this, attributes, options);
}
Więc jeśli już mamy atrybut i jest to zbiór, my go reset()
. Jeśli mamy atrybut, ale nie jest to kolekcja, tworzymy go. Ważne jest, aby poprawnie przetłumaczyć macierz subdanych JSON w kolekcję przed przekazaniem jej do prototypu set()
. Backbone, nie interpretuje tablicy JSON jako kolekcji, a otrzymasz tylko prostą tablicę.
Więc w muszli orzechowej, masz wiele opcji, jak się poruszać. Ponownie, obecnie faworyzuję mieszankę używania initialize()
, gdy wiem, że coś zawsze będzie miało te pod-modele/kolekcje i parse()
, gdy sytuacja wywołuje tylko możliwe zagnieżdżone dane w połączeniach fetch()
.
Odnośnie tego pytania ...(O tak, było pytanie)
Możesz pozwolić Path na tworzenie pod-modeli z hasza na różne sposoby. Właśnie dałem ci 4. Możesz użyć analizy, jeśli chcesz, jeśli wiesz, że masz zamiar być fetch()
modelem ścieżki LUB może nawet ścieżkąCollection ... pathCollection.fetch({parse:true})
Czy istnieje konwencja? Może, może nie. Lubię korzystać z kombinacji sposobów w zależności od kontekstu, w którym myślę, że będę używał modeli/kolekcji.
Jestem bardzo otwarty na dyskusję na temat niektórych z tych praktyk i tego, czy są dobre, czy złe. To tylko wiele rozwiązań, z jakimi spotkałem się na Stack i wcielone w moje własne nawyki pracy i wydaje mi się, że działają dla mnie dobrze. :-)
Napij się kawy i klepnij po plecach, to było długie czytanie.
Czy próbowałeś użyć metody [initialize] (http://documentcloud.github.com/backbone/#Model-constructor)? – Jack
będzie działać, gdy zainicjuję kolekcję, ale co, jeśli samodzielnie zdobędę ścieżkę? Kiedy przyniosę Ścieżkę, już ją zainicjowałem, prawda? – nambrot
Aby wymyślić słowo, myślę, że chcesz przeczytać więcej o "modelach zagnieżdżonych i kolekcjach". – jmk2142