0

我认为我提出问题的方式误导了您,因此我进行了重大编辑。我将使用来自 knockoutjs 教程的代码

“加载和保存数据”,步骤 3

我做了一个改变来表明我的意思。

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 回答