KnockoutJS 绑定在我的视图模型实际创建之前应用

KnockoutJS bindings are applied before my ViewModel is actually created

本文关键字:创建 应用 模型 绑定 我的 视图 KnockoutJS      更新时间:2023-09-26

我认为我提出问题的方式误导了你,所以我做了一个重大编辑。我将使用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 完成初始化应用,因此会导致错误。我想我在代码注释中提供了足够的细节,问我你是否认为你需要更多。无论如何,我有点惊讶以前没有人打过这个东西,所以我在这里错过了一些非常重要的东西吗?

:如何避免这种情况?

小提琴

您有一个 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);    
}