2012-03-09 6 views
6

Próbuję to rozgryźć od jakiegoś czasu. Nie mogłem znaleźć niczego, co rozwiązałoby ten problem, ale popraw mnie, jeśli się mylę.KnockoutJS: Zaktualizuj/wstaw dane do widokuModel za pomocą mapowania

Problem: Mam dane z interfejsu API JSON, wchodzącego w skład zagnieżdżonej struktury tablica/obiekt. Używam mapowania, aby wstępnie wypełnić model z moimi danymi. Aby to zaktualizować, chcę rozszerzyć model, jeśli pojawią się nowe dane, lub zaktualizować istniejące dane.

O ile się dowiedziałem, klucz opcji mapowania, powinien zrobić dla mnie tę sztuczkę, ale mógłbym źle zrozumieć funkcjonalność opcji mapowania.

Mam sprowadzić problem do bycia reprezentowanym przez ten przykład:

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/

Jak widać, pierwsza linia wstawia dane. Wszystko dobrze. Ale kiedy próbuję aktualizować, zastępuje treść. To samo dotyczy trzeciego mapowania; zastępuje treść zamiast ją rozszerzać.

Czy używam go źle? Czy przed użyciem mapowania należy spróbować rozszerzyć zawartość "ręcznie"?

Edycja Rozwiązanie:
I rozwiązać tę sprawę poprzez drugą tablicę pomocnika przechowywania wszystkich aktualnych modeli. Na nowych danych rozszerzyłem tę tablicę i zaktualizowałem model widoku, aby zawierał zgromadzone elementy.

Po aktualizacji (w moim przypadku komunikatu WebSocket), przepuściłem przez modele, zmieniłem zawartość danego elementu i użyłem metody valueHasMutated(), aby powiadomić zmienioną wartość do biblioteki Knockout.

Odpowiedz

4

Od patrząc na przykład kod wtyczki mapowania zachowuje się dokładnie tak, jak ja go się spodziewać. Po wywołaniu fromJS w kolekcji skutecznie informuje się wtyczkę mapującą, że jest to nowa zawartość tej kolekcji. Na przykład:

W drugim wierszu, skąd wiadomo, czy aktualizowałeś lub po prostu usunąłeś id: 2?

Nie mogę znaleźć żadnej wzmianki o odpowiedniej metodzie, która traktuje dane jako zwykłą aktualizację, chociaż można ją dodać. Zmapowane tablice pochodzą z pomocnymi metodami, takimi jak mappedIndexOf, które pomogą ci znaleźć określone przedmioty. Jeśli otrzymasz zestaw danych aktualizacji, po prostu przeprowadź przez niego pętlę, znajdź element i zaktualizuj go wywołując wywołanie JS do tego konkretnego elementu. Można to łatwo uogólnić na metodę wielokrotnego użytku. Metoda

+0

Tak. Mniej więcej tak to rozwiązałem. – mikaelb

+0

Wszelkie przemyślenia na ten temat: http://stackoverflow.com/questions/20397054/knockout-js-mapping-keys-and-kendo-ui-grid – jtromans

0

Tak, należy najpierw zebrać wszystkie dane do listy lub tablicy, a następnie zastosować mapowanie do tej listy. W przeciwnym razie zastąpisz wartości w swoim widokuModelu.

1

Możesz użyć ko.mapping.updateFromJS(), aby zaktualizować istniejące wartości. Jednak nie dodaje nowych wartości, więc byłby to problem w Twojej instancji. Aby uzyskać więcej informacji, zapoznaj się z linkiem poniżej.

Using updateFromJS is replacing values when it should be adding them

+4

W updateFromJS() usunięto w sierpniu 2011. https://github.com/SteveSanderson/knockout.mapping/commit/bff3c1864a5fd45289933b35de1ef70af4aed6b5 – mikaelb

+0

+1 @mikaelb - Nie zdawałem sobie sprawy, że. Dzięki za informację. –