valueHasMutated未按预期工作

mat*_*ser 2 javascript knockout.js

我试图强制UI更新修改一个对象的值observableArray,但数组中的对象不是observable.我以为你可以这样做valueHasMutated,但它没有像我预期的那样工作.

这个例子中,如果我单击更新按钮没有任何反应,但如果我手动重置数组,它会更新:

<div id="bindings">
  <ul data-bind="foreach: observableThings">
    <li data-bind="text: id"></li>
  </ul>
</div>
<button data-bind="click: updateValue">Update</button>
<button data-bind="click: forceUpdate">Force Update</button>
Run Code Online (Sandbox Code Playgroud)
var things = [
  { id: 1, thing: false },  
  { id: 2, thing: false },
  { id: 3, thing: false },
  { id: 4, thing: false }
]

var viewModel = function() {
  var self = this;

  self.observableThings = ko.observableArray(things);

  self.updateValue = function() {
    self.observableThings()[0].id = 5;
    self.observableThings.valueHasMutated();
  }

  self.forceUpdate = function() {
    self.observableThings()[0].id = 5;
    var origThings = self.observableThings();
    self.observableThings(null);
    self.observableThings(origThings);
  }
}

ko.applyBindings(new viewModel());
Run Code Online (Sandbox Code Playgroud)

该怎么valueHasMutated办?

Tom*_*lak 6

将一堆普通对象粘贴到可观察数组中并不会神奇地使这些对象的属性可观察.

可观察数组通常仅观察项目移除和项目插入.如果项目本身具有您想要观察的属性,则显式地需要使这些属性可观察.

映射插件可以与帮助.它可以做一些非常好的事情,请阅读文档页面.

function ListOfThings(params) {
  var self = this;

  self.things = ko.observableArray();

  self.updateValue = function() {
    ko.utils.arrayForEach(self.things(), function (thing) {
      thing.id( ~~(Math.random() * 100) );
    });
  }

  // init
  ko.mapping.fromJS(params, {}, self);
}


var vm = new ListOfThings({
  things: [
    { id: 1, thing: false },  
    { id: 2, thing: false },
    { id: 3, thing: false },
    { id: 4, thing: false }
  ]
});
ko.applyBindings(vm);
Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.min.js"></script>

<div id="bindings">
  <ul data-bind="foreach: things">
    <li data-bind="text: id"></li>
  </ul>
</div>
<button data-bind="click: updateValue">Update</button>

<hr>
<pre data-bind="text: ko.toJSON($root, null, 2)"></pre>
Run Code Online (Sandbox Code Playgroud)


编辑您似乎不成比例地修复valueHasMutated了使用映射插件的不可能性.映射插件很有用,但肯定没有必要.

function Thing(params) {
    this.id =  ko.observable(params.id);
    this.thing = ko.observable(params.thing);
}

function ListOfThings(params) {
  var self = this;

  self.things = ko.observableArray();

  self.updateValue = function() {
    ko.utils.arrayForEach(self.things(), function (thing) {
      thing.id( ~~(Math.random() * 100) );
    });
  }

  // init
  self.things(ko.utils.arrayMap(params.things, function (obj) {
      return new Thing(obj);
  }));
}


var vm = new ListOfThings({
  things: [
    { id: 1, thing: false },  
    { id: 2, thing: false },
    { id: 3, thing: false },
    { id: 4, thing: false }
  ]
});
ko.applyBindings(vm);
Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-min.js"></script>

<div id="bindings">
  <ul data-bind="foreach: things">
    <li data-bind="text: id"></li>
  </ul>
</div>
<button data-bind="click: updateValue">Update</button>

<hr>
<pre data-bind="text: ko.toJSON($root, null, 2)"></pre>
Run Code Online (Sandbox Code Playgroud)

  • 我当然不会删除你问题的唯一正确答案.你问过"为什么这不起作用?" 我告诉你如何正确地做到这一点.*"我如何使用`valueHasMutated`来使它工作?"*是一个红色的鲱鱼和完全没有意义的分心.你甚至不应该尝试这样做,它永远不会工作,这是错误的方式.你不能老实地指望我向你展示如何做错.我告诉你如何正确地做到这一点,这就是我在这里的原因.你似乎无法放弃对"valueHasMutated"的这种痴迷,这就是你的主要问题. (3认同)
  • @mattmanser你甚至在读我写的东西吗?出于基督的考虑,您不需要使用映射插件.**你使用Knockout是错误的,这就是为什么你的代码不起作用.**尝试使用`valueHasMutated`是错误的事情,它将无法正常工作,而且我已经没有办法解决它了.使该数组中的项的属性可观察,一切都将开始工作. (2认同)
  • 我根据Knockout的设计拼写出你如何做到这一点,没有肮脏的黑客或力量,没有映射插件.见修改后的答案. (2认同)