我试图强制UI更新以修改observableArray中的对象的值,但数组中的对象不是observable。我以为您可以使用valueHasMutated做到这一点,但是它没有按我预期的那样工作。

this example中,如果单击“更新”按钮,则没有任何反应,但是,如果我手动重置阵列,它将更新:

<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>

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());
valueHasMutated应该如何工作?

最佳答案

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

可观察的阵列通常仅观察物品的去除和物品的插入。如果项目本身具有您要观察的属性,则必须使这些属性显式可观察。

mapping plugin可以帮助您。它可以做一些非常好的事情,请阅读文档页面。

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);
<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>



编辑您似乎在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);
<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>

10-01 15:12