Javascript 嵌套视图模型结构导致ko中出现错误

Javascript 嵌套视图模型结构导致ko中出现错误,javascript,mvvm,knockout.js,Javascript,Mvvm,Knockout.js,我有一个javascript viewModel,它由一个包含项目列表的模型数据集启动。因为我想从我的页面在项目之间切换,所以我在订阅中收集所有其他数据。selectedProject从中定义所选值。 我通过向Projects数组中的第一个元素启动selectedProject,第一次触发订阅 不知怎的,我得到了错误信息 TypeError: batch is undefined return item.parentID === batch.parentID; ^ 我不明白为什么 这是我的

我有一个javascript viewModel,它由一个包含项目列表的模型数据集启动。因为我想从我的页面在项目之间切换,所以我在订阅中收集所有其他数据。selectedProject从中定义所选值。 我通过向Projects数组中的第一个元素启动selectedProject,第一次触发订阅

不知怎的,我得到了错误信息

TypeError: batch is undefined
return item.parentID === batch.parentID; 
^ 
我不明白为什么

这是我的代码:

ViewModel = function (model)  {
    var self = this;

    self.selectedProject = ko.observable();
    self.selectedText = ko.observable();
    self.Textbatches = ko.observableArray();

    self.Projects = ko.observableArray(
        ko.utils.arrayMap(model, function (item) {
            return new Project(item);
        }));

    self.selectedProject.subscribe(function (project) { 

        /* ...some code... */ 

        $.getJSON("myService/GetTextbatchesFromDB", "projectID=" + project.projectID,
            function (allData) {
               var mappedTextbatches = $.map(allData, function (item) {
                    return new Textbatch(item);
               });
               self.Textbatches(mappedTextbatches);

               self.selectedText(self.Textbatches()[0]);

            }
         ); // End of $.getJSON

        /* ...some more code... */
    }

    self.selectedProject(self.Projects()[0]);  


    self.parentIDFilteredTextbatches = ko.computed(function () {
        var batch = self.selectedText();
        return ko.utils.arrayFilter(self.Textbatches(), function (item) {
            return item.parentID === batch.parentID;   /* ERROR ON THIS LINE */
        });
   });
}
在中:

<script>

    // some code getting "model from the db...

    var viewModel = new ViewModel(model);
    ko.applyBindings(viewModel);
</script>
我发现,如果在初始化self.selectedText后将self.parentIDFilteredTextbatches=ko.computed-functon移动到self.selectedProject.subscribe-function中,则在首次加载页面时,它将起作用


然而,我不喜欢这种视图模型结构,也许我会习惯它,更糟糕的是,在选择新项目时,我会遇到同样的错误,即selectedProject.subscription被触发。

您的问题与MappedTextBatchs变量的范围有关。也可能有轻微的语法错误

由于mappedTextbatches变量的作用域,视图模型的Textbatches属性无权访问该变量。稍后,当您尝试从selectedText属性以局部变量集的形式访问Textbatches[0]的parentID属性时,会出现未定义的错误,因为Textbatches从未实际设置过

有关进一步的解释和示例,请参阅此JSFIDLE:

我无法通过测试来确定,但我猜如果您将代码更改为以下内容,您将不会再收到错误

var mappedTextbatches = $.getJSON("myService/GetTextbatchesFromDB", "projectID=" + project.projectID, function (allData) {
    return $.map(allData, function (item) {
        return new Textbatch(item);
    });
});
编辑以在帖子中反映新代码

在评估之前,继续检查selectedText是否有值。见下文

    self.parentIDFilteredTextbatches = ko.computed(function () {

        if (self.selectedText() !== undefined) {
            var batch = self.selectedText();
            return ko.utils.arrayFilter(self.Textbatches(), function (item) {
                return item.parentID === batch.parentID;   /* ERROR ON THIS LINE */
            });
        }

        return;
    });
虽然我无法确定如何使用提供的信息,但我将假设self.selectedText可以在客户端上进行交互。假设是这样,但不知道更多,一个不太理想的,尽管很快,解决问题的方法是在视图模型顶部将TextBatchs属性声明更改为以下内容。这将减慢对computed函数的通知速度,computed函数保存对TextBatch和selectedText的订阅,希望有足够的时间设置selectedText

self.Textbatches = ko.observableArray().extend({ rateLimit: 500 });
这也将避免您稍后遇到的问题,即在后续客户端更新中,如果您只是执行未定义的检查,您将获得的新TextBatch和旧selectedText之间的不匹配


一个全面的解决方案可能需要根据每个对象所包含的内容重新设计您的数据结构,但我无法从您的帖子中确切地说出每个属性应该代表什么。

克里斯给出了正确的答案。更具体地说,这是:

$.getJSON("myService/GetTextbatchesFromDB", "projectID=" + project.projectID,
    function (allData) {
        var mappedTextbatches = $.map(allData, function (item) {
            return new Textbatch(item);
});
self.Textbatches(mappedTextbatches);
应该是这个吗

var mappedTextbatches;
$.getJSON("myService/GetTextbatchesFromDB", "projectID=" + project.projectID,
    function (allData) {
        mappedTextbatches = $.map(allData, function (item) {
            return new Textbatch(item);
});
self.Textbatches(mappedTextbatches);

范围问题是一个由两部分组成的问题,不是实际问题

最初提供的示例缺少$.getJSON的一些闭包大括号。 $.map闭包上的定位与$.getJSON的定位类似,从视觉上表明实际上不存在范围界定问题。 问题是selectedText不依赖于TextBatchs,并且手动设置为未定义,因为订阅尚未同步到填充TextBatchs。一旦订阅强制对计算的selectedText进行求值,它仍然有一个未定义的文本,现在TextBatchs有实际数据,这将导致执行arrayFilter回调

中的控制台语句说明了代码中的事件序列


另一个

好的,谢谢你。如果你有什么发现,请告诉我。我对MVVM/javascript这件事还很陌生,所以我可能对它缺乏一些基本的了解。我怀疑var mappedTextbatches没有对这个局部变量做任何事情。是否还有另一个您在代码修订中排除的mappedTextbatches声明?我对mappedTextbatches没有问题。Textbatches数组在selectedProject.subscribe运行后获取值。问题是getjson是异步的没有问题!如果我用另一种方式解释的话,也许会有意义。最重要的是,您需要将MappedTextBatchs移动到与设置self.textBatchs相同的级别。现在它位于getJson函数中,因此self.Textbatches无权访问它。当您继续设置self.textbacks时,它会说,好的,将其设置为undefined。稍后,当您尝试访问嵌套属性时,它会说,嘿,这个对象本身是未定义的。我无法访问未定义的属性。正如Origineil指出的,我的示例缺少$getJSON的结尾括号。在我的代码self.textbackesmappedtextbatches中;是在$.getJSON的回调中完成的,因此我想这不是问题所在?我看到您已经更改了上面的代码,但它仍然存在相同的问题。我认为如果您通读JSFIDLE,您将能够理解。
下面是另一个参考,可能有助于了解它们如何解释对carName变量的访问:chrisjsherm self.textbatchesmappedtextbatchs是在$.getJSON调用中设置的。它确实获得了正确的数据。我的问题是self.selectedText。您还有另一个语法错误。另一方面,考虑使用JavaScript链接器来帮助捕捉这些容易出错的错误。它不仅可以帮助您,还可以帮助我们不必猜测您打算在何处创建闭包之类的东西。请确保T大写,并返回新文本。返回项中仍存在错误。parentID==batch.parentID;
var mappedTextbatches;
$.getJSON("myService/GetTextbatchesFromDB", "projectID=" + project.projectID,
    function (allData) {
        mappedTextbatches = $.map(allData, function (item) {
            return new Textbatch(item);
});
self.Textbatches(mappedTextbatches);