【问题标题】:Knockout JS not updating when changing array更改数组时淘汰赛JS不更新
【发布时间】:2017-03-15 21:13:46
【问题描述】:

我知道这个问题已经被问过很多次了,但没有一个回答我的问题。 我有以下内容: 我将数据通过 JSON 转换为 Javascript 到二维数组中。 当我加载网站时,表格会显示出来。 现在,当我单击一个按钮(仅用于测试)时,它正在更新数组中的一个值并将该数组记录在控制台中,在那里我可以看到更改后的数组。 问题是更改未显示在表格中。 当我只是向数组添加一个值时,它会显示在表中。 我做错了什么?

HTML:

<table id="sortsTable">
   <tbody data-bind="foreach: sorts">
   <tr>
     <td data-bind="text: $data.name"></td>
     <td data-bind="text: $data.ingName"></td>
   </tr>
   </tbody>
</table>
<button data-bind="click: addPerson">Add</button>

JS:

var sorts = ko.observableArray([]);

$(function() {
var request = new XMLHttpRequest();
var formData = new FormData();
var responseElements = [];
request.open("POST", "scripts.php", true);
formData.append("action", "getSorts");
request.onreadystatechange = function() {
    if (request.readyState == 4 && request.status == 200) {
        responseElements = JSON.parse(request.responseText);
        sorts = convertList(responseElements);
        ko.applyBindings(new AppViewModel(sorts));
    }
}
request.send(formData);

});

function convertList(response) {  //just the function to convert the json object to a more useful array
    var names = [];
    var ingredients = [];
    var sorts = [];
    for (var index = 0; index < response.length; index++) {
        var name = response[index]['name'];
        var ing = response[index]['ingName'];
        if (names.indexOf(name) == -1) {
            names.push(name);
        }
        if (ingredients.indexOf(ing) == -1) {
            var nameIndex = names.indexOf(name);
            if (ingredients[nameIndex] == undefined) {
                ingredients[nameIndex] = ing;
            } else {
                ingredients[nameIndex] = ingredients[nameIndex] + ", " + ing;
            }
        }
    }
    for (var i = 0; i < names.length; i++) {
        sorts[i] = {};
        sorts[i]['name'] = names[i];
        sorts[i]['ingName'] = ingredients[i];
    }
    return sorts;
}

function AppViewModel(data) {
    var self = this;
    self.sorts = data;
    self.addPerson = function() {
        console.log("click");
        self.sorts[0]["name"] = "test";  //doesn't update table
        //self.sorts.push({name: "qwer", ingName: "we"});  //works like expected
        console.log(self.sorts);
    };
}

谢谢。

【问题讨论】:

  • 可能发生的事情是,knockout.js 正在监视数组的更改,而不是变量的更新。当你添加一个新元素时,你正在改变数组的内容,但是当你更新一个元素时,你正在改变一个变量,但是数组可以保留所有指向它已经拥有的变量的相同指针。您可能需要在淘汰赛中触发刷新事件。
  • 是的,您似乎没有使用任何可观察对象?这真的使得使用淘汰赛毫无意义。我建议你阅读一些淘汰赛教程
  • @JasonSake 我正在使用一个可观察的数组。查看代码的开头。我做得不对吗?
  • @tswei 这个提神怎么办?
  • 您可以在这里尝试解决方案:stackoverflow.com/questions/13231738/…

标签: javascript knockout.js


【解决方案1】:

observable 数组只监控添加了哪些项目,而不是项目本身,所以

self.sorts.push({name: "qwer", ingName: "we"});  //works like expected

之所以有效,是因为您将可观察数组添加到它的项目中,但是

self.sorts[0]["name"] = "test";  //doesn't update table

不起作用,因为可观察数组无法知道其中的项目已更改。为此,数组中项目的属性需要是可观察的。

在convertList中切换到:

for (var i = 0; i < names.length; i++) {
    sorts[i] = {};
    sorts[i]['name'] = ko.observable(names[i]);
    sorts[i]['ingName'] = ko.observable(ingredients[i]);
}

它们必须通过调用 observable setter 方法来设置,如下所示:

self.addPerson = function() {
    console.log("click");
    self.sorts[0]["name"]("test");
    ...

顺便说一句,您似乎还有其他一些问题。您在第一行将 sorts 定义为一个可观察的数组,但是您用 convertList 的返回值覆盖它,它是一个普通数组,而不是一个可观察的数组。

sorts = convertList(responseElements);
ko.applyBindings(new AppViewModel(sorts));

我会删除第一行并将排序创建为可观察数组

function convertList(response) {  //just the function to convert the json object to a more useful array
    var names = [];
    var ingredients = [];
    var sorts = ko.observableArray([]);
    ...

【讨论】:

  • 在 convertList 中切换到:for (var i = 0; i
  • 但是我们这里不是初始化 observable 数组,而是初始化 observables。
  • 嗯,对,我猜没看到。我改变了它,现在由于某种原因数组是空的..所以它根本不输出任何东西
【解决方案2】:

问题是当你绑定这个时:

 <td data-bind="text: $data.name"></td>

$data.name 是不可观察的,它是对象上的一个简单属性,在此处创建:

sorts[i]['name'] = names[i];

Knockout 会很高兴地绑定这样的属性并显示它们,但是对它们的任何更新对于 Knockout 是不可见的。相反,除了您的observableArray,您还需要使任何您希望能够更新的单个属性也可观察:

sorts[i]['name'] = ko.observable(names[i]);

然后当你更新它时,淘汰赛会看到变化。但是请注意,您不能简单地分配给该属性,因为您只会覆盖淘汰赛 observable 并且它将丢失,而是需要 调用 带有更新的 observable:

self.sorts[0]["name"]("test");

【讨论】:

    猜你喜欢
    • 2017-10-26
    • 2014-11-12
    • 2014-10-30
    • 1970-01-01
    • 1970-01-01
    • 2017-11-03
    • 2020-06-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多