【问题标题】:Knockout mapping is not updating my model淘汰赛映射没有更新我的模型
【发布时间】:2014-07-22 16:48:56
【问题描述】:

我遇到了未绑定到订阅更新的淘汰模型的问题。我有一个 C# MVC 页面,该页面将模型交付给模板,该模板被解析为 Json,并作为 ko.applyBindings 的 ViewModel 分配的一部分交付原始数据。我订阅了一个 observable,它调用一个方法来更新 viewModel 的数据。不相关的东西被拉出来并重命名,例如用法:

var myViewModel = function (data) {
    var self = this;

    self.CurrentPage = ko.observable();
    self.SomeComplexArray= ko.observableArray([]);

    self.Pager().CurrentPage.subscribe(function (newPage) {
        self.UpdateMyViewModel(newPage);
    });

    self.UpdateMyViewModel= function (newPage) {
        var postData = { PageNumber: newPage };
        $.post('/Article/GetMyModelSearchByPage', postData, function (data) {
            ko.mapping.fromJS(data, {}, self);;
        });
};

当我执行记录时,我可以看到所有的数据,而且看起来都是正确的。相同的方法用于生成初始模型和更新模型。我在其他页面上使用过这种技术,每次都能完美运行。然而,在这种情况下,我正在寻找它来绑定/更新SomeComplexArray,但这并没有发生。如果我尝试手动执行此操作,则无法在数组上得到正确的绑定,我会得到空白。我想知道是否有什么明显的我做错了,我完全错过了。

编辑:我不知道 ko.mapping 可以被认为是罪魁祸首。标准模型更改也不会影响界面。这是一些在一定意义上不起作用的东西。我有一个可见绑定到数组长度的 p 元素和一个单击绑定到从 SomeComplexArray 中弹出项目的函数的 div 元素。我可以在控制台日志中看到它正在执行其功能(随后的单击导致“未定义”没有该功能)。但是, p 元素永远不会显示。初始数组只有 2 个项目,因此单击即可清空它:

<p data-bind="visible: SomeComplexArray().length === 0">nothing found</p>


<div data-bind="click: function() { UpdateArray(); }">try it manually</div>


-- in js model
self.UpdateArray = function () {
        console.log(self.SomeComplexArray());
        console.log(self.SomeComplexArray().pop());
        console.log(self.SomeComplexArray());
        console.log(self.SomeComplexArray().pop());
        console.log(self.SomeComplexArray());
});

编辑 2: 来自 @Matt Burland 的评论,我修改了 pop 的调用方式,现在手动方法可以动态修改元素。但是, ko.mapping 仍然没有按我的预期运行。在测试中,我在调用 ko.mapping 之前和之后做了一个特定行的 console.log。没有对 observableArray 进行任何更改。

【问题讨论】:

  • 数据是什么样的?它是一个 JavaScript 对象吗?
  • @m.casey:这是一个 JSON 格式的 POCO。在其上使用JSON.parse() 可提供格式正确且可访问的对象。
  • 我问的原因,ko.mapping.fromJS() 期望 'data' 应该是一个 JavaScript 对象,所以如果我们传递 'data' 而 'data' 仍然是一个 JSON 对象时间,它不会起作用的,对吧?此外,不确定这是否只是复制/粘贴问题,但映射语句末尾存在语法错误,并且 $.post 函数后缺少“}”。
  • @m.casey:从控制器返回的对象与在页面加载时加载的对象相同(除了其中的数据)。如果该对象无论如何都是格式错误的,它会在 console.log 中给我一个错误(当我尝试各种想法让它工作时,它发生了几次)。
  • self.SomeComplexArray().pop() 替换为self.SomeComplexArray.pop(),您的编辑将生效。当您执行 self.SomeComplexArray() 时,您将返回 not 可观察的常规 JS 数组。如果你想让 KO 看到你的数组的变化,你必须使用 observable 数组本身和它的函数。见:jsfiddle.net/AdGe3

标签: asp.net-mvc knockout.js


【解决方案1】:

我在JSFiddle 中创建了一个测试你的淘汰赛情况。

你必须在没有括号的情况下调用你的数组函数。我测试了这部分:

self.UpdateArray = function () {

        self.SomeComplexArray.pop();

};

它似乎在 JSFiddle 方面工作。

【讨论】:

  • 在@MattBurland 的一些 cmets 之后,这个手动测试确实有效。但是,原来的 ko.mapping 仍然无法正常工作。
  • @JoelEtherton,我发现了你的问题。你可以查看我更新的答案。
  • 这不是问题。那只是我用来测试界面更新的东西,就像我说的,来自 MattBurland 的 cmets 帮助我纠正了这个问题。问题在于 ko.mapping 没有按照初始代码示例中的定义运行。
【解决方案2】:

我不太确定为什么,但似乎 ko.mapping 根本无法重新映射视图模型。由于没有一个字段被映射到self,我的假设是在某个地方发生了一个异常,ko.mapping 只是在吞咽,或者由于其他原因没有被报告。鉴于我可以使用来自@MattBurland 的有用提示手动操作数组,我决定回溯一点,只更新需要在数据加载时直接更改的元素。我最终为我的 viewModel 创建了一个 Init 函数并使用 ko.mapping 直接在那里填充项目:

self.Init = function (jsonData) {
    self.CurrentPage(0);
    self.Items(ko.mapping.fromJS(jsonData.Items)());
    self.TotalItems(jsonData.TotalItems);
    // More stuff below here not relevant to question
}

这里的主要区别是 ko.mapping.fromJS 结果需要在 observableArray 将其识别为函数之前作为函数调用。鉴于这有效,并且我的控制器将在 AJAX 请求期间提供相同的对象,它几乎是复制/过去:

self.UpdateMyViewModel= function (newPage) {
    var postData = { PageNumber: newPage };
    $.post('/Article/GetMyModelSearchByPage', postData, function (data) {
        self.Items(ko.mapping.fromJS(JSON.parse(data).Items)());
    });
};

这对于大多数情况可能并不理想,但由于在更新期间不会对 viewModel 进行大量操作,这提供了一个可行的解决方案。我仍然想知道为什么 ko.mapping 不会在顶层重新映射 viewModel,但回想起来这可能会是一场灾难,因为 viewModel 中存在服务器必须替换的“修改”数据。这个解决方案既快速又简单。

【讨论】:

    猜你喜欢
    • 2013-09-30
    • 1970-01-01
    • 2016-03-13
    • 1970-01-01
    • 2012-06-08
    • 1970-01-01
    • 1970-01-01
    • 2012-12-05
    • 2015-03-30
    相关资源
    最近更新 更多