2012-03-09 12 views
6

Ho cercato di capirlo per un po 'di tempo. Non sono riuscito a trovare nulla che risolva questo problema, ma per favore correggimi se sbaglio.KnockoutJS: Aggiorna/Inserisci dati a viewModel utilizzando la mappatura

Il problema: Ho dati da un'API JSON che entra, con una struttura di array/oggetto nidificata. Uso la mappatura per riempire inizialmente il modello con i miei dati. Per aggiornarlo, voglio estendere il modello se arrivano nuovi dati o aggiornare i dati esistenti.

Per quanto ho scoperto, la chiave opzione mappatura, dovrebbe fare questo trucco per me, ma potrei aver frainteso la funzionalità delle opzioni di mappatura.

ho bollito giù il problema di essere rappresentati da questo esempio:

var userMapping = { 
    key: function(item) { 
     return ko.utils.unwrapObservable(item.id); 
    } 
}; 

// JSON call replaced with values 
var viewModel = { 
    users: ko.mapping.fromJS([], userMapping) 
}; 

// Should insert new - new ID? 
ko.mapping.fromJS([{"id":1,"name":"Foo"}, {"id":2,"name":"Bar"}], userMapping, viewModel.users); 

// Should only update ID#1 - same ID? 
ko.mapping.fromJS([{"id":1,"name":"Bat"}], userMapping, viewModel.users); 

// Should insert new - New ID? 
ko.mapping.fromJS([{"id":3,"name":"New"}, {"id":4,"name":"New"}], userMapping, viewModel.users); 

ko.applyBindings(viewModel);​ 

Fiddle: http://jsfiddle.net/mikaelbr/gDjA7/

Come si può vedere, la prima linea inserisce i dati. Tutto bene. Ma quando provo ad aggiornare, sostituisce il contenuto. Lo stesso per la terza mappatura; sostituisce il contenuto, invece di estenderlo.

Sto usando male? Dovrei provare ad estendere il contenuto "manualmente" prima di usare la mappatura?

Edit Soluzione:
Ho risolto questo caso avendo un secondo array helper memorizzare tutti i modelli attuali. Sui nuovi dati ho esteso questo array e aggiornato il modello di visualizzazione per contenere gli elementi accumulati.

In caso di aggiornamento (nel mio caso un messaggio WebSocket), ho fatto il looping dei modelli, modificato il contenuto dell'elemento in questione e ho utilizzato il metodo valueHasMutated() per dare notifica del valore modificato alla lib di Knockout.

risposta

4

Guardando il codice di esempio, il plug-in mapping si sta comportando esattamente come mi sarei aspettato a. Quando chiami fromJS su una raccolta stai dicendo efficacemente al plugin di mappatura questo è il nuovo contenuto di quella raccolta. Ad esempio:

Sulla seconda riga, come poteva sapere se stavi aggiornando o se avevi semplicemente rimosso id: 2?

Non riesco a trovare alcuna menzione di un metodo adatto che tratta i dati semplicemente come un aggiornamento, sebbene sia possibile aggiungerne uno. Gli array mappati vengono forniti con alcuni metodi utili come mappedIndexOf per aiutarti a trovare elementi particolari. Se si riceve un set di dati di aggiornamento, è sufficiente scorrere ciclicamente, trovare l'elemento e aggiornarlo con una mappatura dalla chiamata JS a quel particolare oggetto. Questo può essere facilmente generalizzato in un metodo riutilizzabile. Metodo

+0

Sì. Questo è più o meno come l'ho risolto. – mikaelb

+0

Qualsiasi idea al riguardo: http://stackoverflow.com/questions/20397054/knockout-js-mapping-keys-and-kendo-ui-grid – jtromans

0

Sì, è necessario innanzitutto raccogliere tutti i dati in un elenco o matrice e quindi applicare la mappatura a tale elenco. In caso contrario, sovrascriverai i valori nel tuo viewModel.

1

È possibile utilizzare ko.mapping.updateFromJS() per aggiornare i valori esistenti. Tuttavia, non aggiunge nuovi valori, quindi sarebbe un problema nella tua istanza. Dai un'occhiata al link sottostante per maggiori dettagli.

Using updateFromJS is replacing values when it should be adding them

+4

I updateFromJS() è stato rimosso nel mese di agosto 2011. https://github.com/SteveSanderson/knockout.mapping/commit/bff3c1864a5fd45289933b35de1ef70af4aed6b5 – mikaelb

+0

+1 @mikaelb - Non mi rendevo conto che. Grazie per le informazioni. –

Problemi correlati