0

質問の仕方が誤解を招いたと思いますので、大幅な編集を行いました。knockoutjs チュートリアルのコードを使用します

「データの読み込みと保存」、手順 3

私が言いたいことを示すために、1 つの変更を加えました。

function Task(data) {
    this.title = ko.observable(data.title);
    this.isDone = ko.observable(data.isDone);
}

function TaskListViewModel() {
    // Data
    var self = this;
    self.tasks = ko.observableArray([]);
    self.newTaskText = ko.observable();
    self.incompleteTasks = ko.computed(function() {
        return ko.utils.arrayFilter(self.tasks(), function(task) { return !task.isDone() });
    });

    // Operations
    self.addTask = function() {
        self.tasks.push(new Task({ title: this.newTaskText() }));
        self.newTaskText("");
    };
    self.removeTask = function(task) { self.tasks.remove(task) };

    // ** Read this!!
    // This below is the original code in the tutorial, used to fetch remote data.
    // I commented this out, and i will use the below load() method instead.
    // **
    //$.getJSON("/tasks", function(allData) {
    //    var mappedTasks = $.map(allData, function(item) { return new Task(item) });
    //    self.tasks(mappedTasks);
    //});

    // This is the load method to emulate the above commented
    // $.get. Please, DO NOT CARE about the implementation, or
    // the setTimeout usage, etc., this method ONLY EXISTS TO
    // EMULATE A SLOW SERVER RESPONSE.
    // So, we have to ways of using it:
    //     - load('slow'), will set result after 1 second
    //     - any other argument will set result instantly.
    self.load = function(howFast) {
        if (howFast == 'slow') {
            setTimeout(function(){
                mappedTasks = [];
                mappedTasks.push(new Task({
                    title: 'Some task slowly loaded from server', 
                    isDone: false
                }));
            }, 1000);
        } else {
             mappedTasks = [];
             mappedTasks.push(new Task({
                 title: 'Some task quick!', 
                 isDone: false
             }));
        }
    }

    // Now please note this:
    // - if i use load(), mappedTask is instant updated and
    //   everything runs fine
    // - if i use load('slow'), mappedTask is updated AFTER
    //   VALUES ARE BOUND, so if you open your browser console
    //   you will see an "Uncaught ReferenceError: mappedTasks is not defined" error.
    self.load();
    self.tasks(mappedTasks);
}


ko.applyBindings(new TaskListViewModel());

問題: ViewModelが初期化を行った後にバインディングが適用されるため、エラーが発生します。コードのコメントで十分な詳細を提供したと思います。さらに必要な場合はお問い合わせください。とにかく、これまで誰もこれを打ったことがないことに少し驚いているので、ここで非常に重要なことを見逃していますか?

質問: これを回避するにはどうすればよいですか?

フィドル

4

1 に答える 1

0

html エラーがあります。

setTimeout 関数は、選択したオプションを、リストにないオプションにプログラムで設定しようとしています。ブラウザはそれを行うことができないため、選択はそのまま残ります。

http://jsfiddle.net/UD89R/6/

function ViewModel() {
    // Setup something.
    var self = this;
    self.foo = ko.observable();
    self.options = ko.observableArray([{id:1, name:'Homer'}, {id:2, name:'Barney'}]);

    // Make a lot of async data load, like    
    // $.get('this', function(){  /* Process data */ });
    // $.get('that', anotherHandler);
    // $.get('somethingElse', self.someObservable);

    // Assume the whole process would take 1 second.
    setTimeout(function(){
        self.options.push({id: 3, name: 'Grimes'});
        self.foo(3);
        // Too late! foo has been overriden by the select-options binding,
        // so this one will not log 'Grimes' as expected.
        console.log('Loading done, check foo value:' + self.foo());
    }, 1000);    
}
于 2013-10-29T23:10:51.307 に答える