问题
I have a view model that fetches JSON through AJAX, and creates a new Task, but Knockout keep giving me a binding error.
If I hard code the data coming from the server straight in my view model, I don't receive any errors.
My view model creates new task, that has an id, a question and a number of alteratives, which in itself has a text and correct boolean flag.
The following code works perfectly fine:
function Task(data) {
var self = this;
self.id = data.id;
self.question = ko.observable(data.question);
var alts = new Array();
$(data.alternatives).each(function(index){
alts.push(new Alternative(data.alternatives[index].alternative, data.alternatives[index].correct));
});
self.alternatives = ko.observableArray(alts);
}
function Alternative(alternativeText, correctAnswer) {
var self = this;
self.alternative = ko.observable(alternativeText);
self.correct = ko.observable(correctAnswer);
}
function TaskViewModel() {
var self = this;
var data = {
id: 5,
question: 'test',
alternatives: [{
alternative: 'alt 1',
correct: false
},{
alternative: 'alt 2',
correct: true
},{
alternative: 'alt 3',
correct: false
}]
};
self.task = new Task(data);
}
But if I exhcange the hard coded data
variable with real data from the server:
function TaskViewModel() {
var self = this;
$.getJSON('/data', function(data){
self.task = new Task(data);
});
}
Knockout gives me this error:
Error: Unable to parse bindings.
Message: ReferenceError: Can't find variable: task;
Bindings value: value: task.question
The data from the URL looks like the following:
{"id":5,"question":"test","alternatives":[{"alternative":"alt 1","correct":false},{"alternative":"alt 2","correct":true},{"alternative":"alt 3","correct":false}]}
I can't seem to figure out why this won't work :/
回答1:
Your view model doesn't actually have a task
property by the time your bindings are applied. You need to give it something to bind to.
There's a couple of ways you can handle this.
Probably the easiest way would be to make task
observable and set it as the result of the ajax call. You may need to adjust you bindings to account for this change.
function TaskViewModel() {
var self = this;
self.task = ko.observable();
$.getJSON('/data', function(data){
self.task(new Task(data));
});
}
A more flexible option would be to add a separate initialization method for your Task
objects and set the task (uninitialized). Then as a result of the ajax call, call the initialization method to initialize it. You would have to adjust the initialization code for your task objects of course.
function TaskViewModel() {
var self = this;
self.task = new Task();
$.getJSON('/data', function(data){
self.task.init(data);
});
}
function Task() {
var self = this;
self.id = ko.observable();
self.question = ko.observable();
self.alternatives = ko.observableArray();
self.init = function (data) {
self.id(data.id);
self.question(data.question);
self.alternatives(ko.utils.arrayForEach(data.alternatives, function (item) {
return new Alternative(item.alternative, item.correct);
}));
};
}
回答2:
This post contains a number of ways you can handle binding when source is null.
KnockoutJS binding when source is null/undefined
If you're OK with your unbindable UI from disappearing I recommend using with
If selectedItem
is null then the element won't even be shown.
<div data-bind="with: selecteditem">
<form>
<fieldset>
<div>
<label>first name</label>
<input data-bind="value: firstname"></input>
</div>
<div>
<label>lasst name</label>
<input data-bind="value: lastname"></input>
</div>
</fieldset>
<div>
<a href="#" data-bind="click: $root.savechanges">Save</a>
</div>
</form>
</div>
来源:https://stackoverflow.com/questions/13333567/knockout-js-unable-to-parse-bindings-from-json