2016-03-26 8 views
1

Mein Beispiel funktioniert, aber ich bin verwirrt über den Speicherort der Anweisung ko.applyBindings(). Ich habe this approach verwendet, um mein ViewModel von einer einzigen getJSON-Anfrage zu füllen. Aber angenommen, ich brauche 2 getJSON-Anfragen. Ich habe das "var viewModel = new MyViewModel();" außerhalb der getJSON, aber die ko.applyBinding() war in beiden Methoden getJSON, und ich verstehe, dass Sie nicht 2 Bindungen an die gleiche VM haben sollte. Ich habe versucht, die ko.applyBinding() unter dem getJSON zu bewegen, aber nichts hat funktioniert. Also habe ich ko.applyBinding() in einer der getJSON-Methoden gelassen und VM-Methode aufgerufen, um die Variable aus dem anderen JSON-Aufruf zu setzen. Es scheint zu funktionieren, aber ich bin besorgt, wenn es ein Timing-Problem gibt, das Probleme verursachen kann, wenn die JSON-Anfragen zu unterschiedlichen Zeiten zurückkehren.Knockout.js Bindung mit mehreren getJSON-Anfragen

var MyViewModel = function() { 
    var self = this; 
    self.types = ko.observableArray(); 
    self.states = ko.observableArray(); 
    self.loadStates = function (states){ 
     self.states = states; 
    } 
} 
var viewModel = new MyViewModel(); 
$(function() { 
    $.getJSON('json/typeArray.json', function(jTypes){ 
     viewModel.types = jTypes; 
     ko.applyBindings(viewModel); 
    }); 
    $.getJSON('json/stateArray.json', function(jStates){ 
     viewModel.loadStates(jStates); 
     //ko.applyBindings(viewModel); 
    }); 
}); 

Ich könnte verschachtelte JSON-Anfragen verwenden, aber ich würde es vorziehen, sie zur gleichen Zeit auszuführen.

Warum kann das ko.applyBindings (viewModel) nicht an das Ende dieses Skripts verschoben werden? Ich habe es versucht, aber keines meiner Arrays wird aufgefüllt.

Update: Ja, es gibt ein Timing-Problem. Manchmal wird das zweite "states" -Array in der Benutzeroberfläche aktualisiert, und manchmal nicht. Es hängt offenbar davon ab, welcher getJSON zuerst zurückkehrt. Also muss ich eine Lösung für dieses Problem finden.

Hier ist der Versuch, die applyBindings nach Ansichtsmodell Schöpfung zu bewegen, was nicht (siehe Kommentar) funktionierte:

var MyViewModel = function() { 
    var self = this; 
    self.name = "myViewModel"; 
    self.states = ko.observableArray(); 
    self.types = ko.observableArray(); 
    self.loadStates = function (states){ 
     self.states = states; 
     console.log("Set states in viewModel: " + self.states); 
    } 
} 

var viewModel = new MyViewModel(); 
ko.applyBindings(viewModel); 

$(function() { 
    $.getJSON('json/typeArray.json', function(jTypes){ 
     console.log("Setting types in viewModel: " + viewModel.name); 
     viewModel.types = jTypes; 
     //ko.applyBindings(viewModel); 
    }); 
    $.getJSON('json/stateArray.json', function(jStates){ 
     console.log("Setting states in viewModel: " + viewModel.name); 
     viewModel.loadStates(jStates); 
     //ko.applyBindings(viewModel); 
    }); 
}); 
+0

applyBindings sollte einmal aufgerufen werden, z. unmittelbar nach der Erstellung von viewModel. Sie sollten beobachtbare Eigenschaften in der Funktion get json done aktualisieren: viewModel.types (jTypes) - ich nehme an, dass jTypes ein Array ist. – TSV

+0

Ich habe versucht, die applyBindings nach der Erstellung von viewModel zu setzen, aber die Arrays werden nie auf der HTML-Seite aktualisiert. Wenn ich die applyBindings im getJSON auskommentiere, funktioniert es gut. Beachten Sie, dass die Einträge in console.log angeben, dass das viewModel in allen Fällen ordnungsgemäß aktualisiert wird. –

+0

Zusätzlich zu dem, was @TSV sagt, können Sie 'Promise.all()' verwenden, um sicherzustellen, dass alle Ihre json geladen sind, bevor Ihr Callback aufgerufen wird: siehe Beispiel https://jsfiddle.net/axLokczs/2/ – Michael

Antwort

1

Die Sache ist, dass Sie für beobachtbare Arrays neue Werte festlegen und den gebundenen Eigenschaften kein neues Objekt zuweisen.

Statt zuweisen:

viewModel.types = jTypes; 

Ich schlage vor, die Aktualisierung zu verwenden:

//viewModel.types(jTypes); 
viewModel.types(["type a", 'type b', 'type c']); 

Ich habe eine Probe erstellt (Anforderung über SetTimeout emuliert wird), beim Start-Arrays sind leer, „mal "werden in 1 Sekunde aktualisiert, "Zustände" werden in 2 Sekunden aktualisiert:

var MyViewModel = function() { 
 
    var self = this; 
 
    self.name = "myViewModel"; 
 
    self.states = ko.observableArray(); 
 
    self.types = ko.observableArray(); 
 
} 
 

 
var viewModel = new MyViewModel(); 
 
ko.applyBindings(viewModel); 
 

 
//$(function() { 
 
// $.getJSON('json/typeArray.json', function(jTypes){ 
 
//  viewModel.types(jTypes); 
 
// }); 
 
// $.getJSON('json/stateArray.json', function(jStates){ 
 
//  viewModel.states(jStates); 
 
// }); 
 
//}); 
 

 
//$.getJSON('json/typeArray.json', function(jTypes){ 
 
setTimeout(function() { 
 
    viewModel.types(["type a", 'type b', 'type c']) 
 
}, 1000); 
 

 
//$.getJSON('json/stateArray.json', function(jStates){ 
 
setTimeout(function() { 
 
    viewModel.states(["state d", 'state e', 'state f']) 
 
}, 2000); 
 

 
// ever more - update types again in 5 sec 
 
//$.getJSON('json/typeArray.json', function(jTypes){ 
 
setTimeout(function() { 
 
    viewModel.types(["type g", 'type h', 'type i', 'type j']) 
 
}, 5000);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script> 
 

 
<div>States:</div> 
 
<!-- ko if: states().length === 0 --> 
 
<div>There are no states for a while...</div> 
 
<!-- /ko --> 
 
<!-- ko foreach: states --> 
 
<div data-bind="text: $data"></div> 
 
<!-- /ko --> 
 
    
 
<div>Types:</div> 
 
<!-- ko if: types().length === 0 --> 
 
<div>There are no types for a while...</div> 
 
<!-- /ko --> 
 
<!-- ko foreach: types --> 
 
<div data-bind="text: $data"></div> 
 
<!-- /ko -->

+0

Hey Leute, warum downvote? – TSV

+0

Funktioniert perfekt. Das asynchrone getJSON() sollte kein Problem mit dem ObservableArray verursacht haben - weshalb ich verwirrt war. Aber ich habe das OBJECT zurückgesetzt und das neue Objekt (jTypes) konnte nicht beobachtet werden. Ich musste die WERTE des aktuellen Objekts einstellen, und ich wusste einfach nicht, wie ich das machen sollte. Das Ersetzen der = mit viewModel.types (jTypes) hat den Job erledigt. Die "Promise" -Technik ist großartig, wenn Sie auf die Ausführung der Anforderungen warten müssen, aber das war hier nicht der Fall. Danke für die richtige Lösung und das laufende Code-Snippet. –

0

Beachten Sie, dass ich in dieser Antwort habe einen grundlegenden ausdrücklich das Rad neu zu erfinden, um zu zeigen, Konzept dafür, wie das funktionieren könnte. Es gibt Bibliotheken, einschließlich derjenigen, die Sie bereits verwenden (jQuery), die diese Aufgabe viel einfacher und flüssiger machen.

Grundsätzlich möchten Sie ko.applyBindings ausführen, aber erst nach zwei separaten asynchronen Anforderungen abgeschlossen sind. Hier ist ein Muster zu tun, dass:

var viewModel = new MyViewModel(); 

function tryApplyBindings() { 
    if (viewModel.types().length > 0 && 
     viewModel.states().length > 0) { 
    ko.applyBindings(viewModel); 
    } 
} 

$(function() { 
    $.getJSON('json/typeArray.json', function(jTypes){ 
     console.log("Setting types in viewModel: " + viewModel.name); 
     viewModel.types = jTypes; 
     tryApplyBindings(); 
    }); 
    $.getJSON('json/stateArray.json', function(jStates){ 
     console.log("Setting states in viewModel: " + viewModel.name); 
     viewModel.loadStates(jStates); 
     tryApplyBindings(); 
    }); 
}); 

jedoch wieder: beachten Sie, dass dies das Rad neu erfindet. Sie können die Versprechen Features von jQuery (z. B. mit this approach, vielleicht) verwenden, um eine elegantere und trockenere Kombination von Versprechen zu machen.


Als Fußnote könnte man auch erwägen applyBindings direkt, und erstellen Sie eine Ansicht ausgeführt wird, als auch mit leeren Arrays schön aussieht. Wenn die Versprechen dann zurückkehren, wird die Benutzeroberfläche automatisch aktualisiert.