Knockout.js: невозможно проанализировать привязки из JSON

У меня есть модель представления, которая извлекает JSON через AJAX и создает новую задачу, но Knockout продолжает выдавать мне ошибку привязки.

Если я жестко кодирую данные, поступающие с сервера, прямо в мою модель представления, я не получаю никаких ошибок.

Моя модель представления создает новую задачу с идентификатором, вопросом и рядом альтернатив, которая сама по себе имеет текст и правильный логический флаг.

Следующий код работает отлично:

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);
}

Но если я заменю жестко закодированную переменную data реальными данными с сервера:

function TaskViewModel() {
    var self = this;

    $.getJSON('/data', function(data){
        self.task = new Task(data);
    });
}

Нокаут дает мне эту ошибку:

Error: Unable to parse bindings.
Message: ReferenceError: Can't find variable: task;
Bindings value: value: task.question

Данные из URL выглядят следующим образом:

{"id":5,"question":"test","alternatives":[{"alternative":"alt 1","correct":false},{"alternative":"alt 2","correct":true},{"alternative":"alt 3","correct":false}]}

Я не могу понять, почему это не сработает :/


person rebellion    schedule 11.11.2012    source источник


Ответы (2)


Ваша модель представления на самом деле не имеет свойства task к моменту применения ваших привязок. Вам нужно дать ему что-то для привязки.

Есть несколько способов справиться с этим.

Вероятно, самым простым способом было бы сделать task наблюдаемым и установить его как результат вызова ajax. Возможно, вам придется настроить свои привязки, чтобы учесть это изменение.

function TaskViewModel() {
    var self = this;
    self.task = ko.observable();

    $.getJSON('/data', function(data){
        self.task(new Task(data));
    });
}

Более гибким вариантом было бы добавить отдельный метод инициализации для ваших Task объектов и задать задачу (неинициализированную). Затем в результате вызова ajax вызовите метод инициализации для его инициализации. Конечно, вам придется настроить код инициализации для ваших объектов задач.

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);
        }));
    };
}
person Jeff Mercado    schedule 11.11.2012
comment
Спасибо чувак. Я действительно понял это после того, что вы упомянули с помощью метода инициализации (который вы представили здесь). Это заставило его работать отлично :) - person rebellion; 12.11.2012

Этот пост содержит несколько способов обработки привязки, когда источник имеет значение null.

Привязка KnockoutJS, когда источник имеет значение null/undefined

Если вас устраивает исчезновение непривязываемого пользовательского интерфейса, я рекомендую использовать with.

Если selectedItem равно нулю, элемент даже не будет отображаться.

<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>
person Simon_Weaver    schedule 26.04.2013
comment
примечание: с помощью этого метода этот div удаляется из DOM, когда selecteditem имеет значение null, поэтому, если к нему прикреплены не «живые» обработчики событий, он может не работать - person Simon_Weaver; 27.04.2013