2012-07-02 11 views
37

Chciałbym wiedzieć, jak utworzyć obliczoną tablicę obserwowalne.Jak utworzyć obliczyć tablicę obserwowalną w Knockout

W moim modelu widoku mam 2 tablice obserwowalne i chciałbym mieć obliczyć tablicę obserwowalną, która jest po prostu połączonymi obydwoma tablicami.

function ViewModel() { 
    var self = this; 
    self.listA= ko.observableArray([]); 
    self.listB = ko.observableArray([]); 
    self.masterList= //combine both list A and B 

Odpowiedz

33

to będzie połączenie tych dwóch tablic i powrót połączonej listy. Jednak nie jest to obliczona tablica obserwowalna (nie wiem, czy to nawet możliwe), ale można zaobserwować regularne obliczenia.

self.masterList = ko.computed(function() { 
    return this.listA().concat(this.listB()); 
}, this); 
+18

wierzę ta odpowiedź jest wadliwa dla większości przypadków użycia: wartość wyliczonego obserwowalnego jest regularną tablicą, a nie tablicą obserwowalną (z grubsza określoną w odpowiedzi). Dlatego aktualizacja 'listA' lub' listB' całkowicie zastąpi samą tablicę zamiast aktualizować jej zawartość (czego chcemy w 99% przypadków). ** Oznacza to, że nie powinieneś wiązać widoków z tym obserwowalnym. ** W efekcie ten kod jest tak samo użyteczny, jak jego niewykonany wariant. Zobacz inne odpowiedzi dla różnych podejść. – tne

+0

Nie zadziała w tym przypadku, ale wtyczka knockout [knockout-projections] (https://github.com/stevesanderson/knockout-projections) implementuje znacznie bardziej wydajne obliczalne obserwowalne tablice za pomocą newish [array change subcriptions] (http://blog.stevensanderson.com/2013/10/08/knockout-3-0-release-candidate-available/). Tę wtyczkę można rozszerzyć, aby obsługiwała wydajną operację konkatycji. – Singularity

7

ObservableArray jest obserwowalny z kilkoma innymi właściwościami. Dlatego obliczona obserwowalna, która zwraca tablicę w zamknięciu, będzie traktowana jako tablica.

+3

Cóż, rodzaj. Właśnie to przetestowałem i wygląda na to, że jeśli nie zostanie zadeklarowana jako tablica obserwowalna, metody takie jak shift i pop nie są dla ciebie. – Eirinn

9

wiem, że to jest stare pytanie, ale pomyślałem, że rzucam moją odpowiedź tam:

var u = ko.utils.unwrapObservable; 

ko.observableArray.fn.filter = function (predicate) { 
    var target = this; 

    var computed = ko.computed(function() { 
     return ko.utils.arrayFilter(target(), predicate); 
    }); 

    var observableArray = new ko.observableArray(u(computed)); 

    computed.subscribe(function (newValue) { observableArray(newValue); }); 

    return observableArray; 
}; 
10
self.masterList = ko.observableArray(); 
ko.computed(function() { 
    self.masterList(self.listA().concat(self.listB())); 
}); 

podobne do odpowiedzi Joe Flateau w duchu, ale podoba mi się, że ta metoda jest prostsza .

+0

Tak też miałem zamiar to zrobić, ale czy nie jest to problem z zaakceptowaną odpowiedzią; w jakiejkolwiek zmianie spowoduje to, że wszelkie widoki związane z 'masterList' zostaną całkowicie odrysowane? –

+0

@AdamLewis: Tak, to rzeczywiście odbudowuje całą tablicę iw zależności od mechanizmu widoku może, ale nie musi, ponownie renderować cały podgraph DOM, niezależnie od tego, jakie widoki są z nim związane (niekoniecznie, może po prostu zrobić różnicę i zastosować to). Należy pamiętać, że nadal może być najlepszym rozwiązaniem, aby uniknąć wielu aktualizacji. Nie jest to kwestia, którą nakreśliłem w odniesieniu do odpowiedzi, o której wspomniałeś, ale jeśli silnik widokowy przechwytuje samą właściwość tablicową (w przeciwieństwie do ścieżki do niej), to nigdy nie wykryłaby zamiany tablicy (ponieważ nie jest widoczna) i w ten sposób nigdy nie zaktualizuje * w ogóle *. – tne

+0

@tne Używam tej odpowiedzi na razie, ale wydaje się to bardzo powolne ... może robię coś złego. jednak czy to rozwiązanie przełamuje zamierzony cel KO?czy istnieje inny sposób rozwiązania problemu wymagającego obliczonej tablicy obserwowalnej? tylko zastanawiam się, czy jest to odpowiednie narzędzie do użycia w mojej (lub dowolnej) sytuacji. – Nate

2

Nie jestem pewien, czy jest to najbardziej wydajna opcja - ale jest dość prosta i działa dla mnie. W ko.computed Zwraca obserwowalne array jak poniżej:

self.computedArrayValue = ko.computed(function() { 
    var all = ko.observableArray([]); 
    .... 
    return all(); 
}); 

przykład roboczych kodu: HTML:

<div data-bind="foreach: days"> 
    <button class="btn btn-default btn-lg day" data-bind="text: $data, click: $root.dayPressed"></button>   
</div> 

funkcji JavaScript na modelu Widok:

self.days = ko.computed(function() { 
    var all = ko.observableArray([]); 
    var month = self.selectedMonth(); //observable 
    var year = self.selectedYear();  //observable 
    for (var i = 1; i < 29; i++) { 
     all.push(i); 
    } 
    if (month == "Feb" && year % 4 == 0) { 
     all.push(29); 
    } else if (["Jan","Mar","May","Jul","Aug","Oct","Dec"].find((p) => p == month)) { 
     [29,30,31].forEach((i) => all.push(i)); 
    } else if (month != "Feb") { 
     [29,30].forEach((i) => all.push(i));     
    } 
    return all(); 
}); 
Powiązane problemy