【发布时间】:2015-10-16 12:36:21
【问题描述】:
当我对我的 observable 数组执行 push 或 pop 操作时,它会反映在 ui.xml 中。然而,数组上的其他操作不会改变 UI 中的任何内容。这是我的一个例子:
<ul data-bind="foreach: addresses">
<!-- ko template: {name: 'AddressItemTemplate', data: {address: $data, page: 'update-page'} }-->
<!-- /ko -->
</ul>
我在两个不同的页面中使用我的模板,这就是我使用这样的模板数据的原因。
<script type="text/html" id="AddressItemTemplate">
<p data-bind="text: (page == 'update-page') ? 'updating' : 'declined'"</p>
<p data-bind="text: address.title"></p>
</script>
现在在 js 方面,我将地址声明为可观察数组
this.addresses = ko.observableArray([addresObject1, addressObject2, ...])
在页面的某处,我编辑了地址值。为了让 UI 反映更改,我执行以下操作:
//suppose we know that the first address is being edited
var tmp_addresses = addresses();
tmp_addresses[0].title = 'blabla';
addresses(tmp_addresses);
还有,在 viewModel 中,我可以看到 addresses 的内容已经更新,但在 UI 中没有??
addresses.push(someAddressObject);
或
addresses.pop();
有效(使用新的/删除的元素更新 UI)。但是addresses.splice(0, 1, newAddressObject) 不再在 UI 中做任何事情。
我在这里缺少什么?如何推动流行工作而不是其他工作? 我是否遇到了淘汰赛框架中的错误?
更新
我找到了一种方法,但是出了点问题。我会先说到这里:
我很清楚,如果我在可观察数组中使用可观察对象,更改将反映在 UI 中。然而这正是我想要避免的事情。这是一种矫枉过正。
在属性真正暴露给用户交互的情况下,应该需要可观察的属性。例如,如果您有一个用于设置对象的每个字段的 UI,那么是的,observable 属性将是正确的调用。
但是,就我而言,我什至没有用于更新地址字段的 UI。此外,我不需要修补和不断观察所有地址的所有属性。就我而言,服务器不时会发生更新,并且仅更改单个地址字段中的单个字段。
从另一个角度来看我建议的方式应该可行。我只是一次更新整个数组,而不是单独更新每个元素。这与以下逻辑完全相同:
someObservableObject({newObject: withNewFields, ...});
这就是为什么我不需要我的对象作为可观察对象。我只是想重新声明数组并完成更改。例如,建议如果您要对可观察数组进行大量推送,不要多次使用 array.push(...),而是将较大的数组重新声明到可观察数组变量 在我的问题中以类似的方式进行。否则,我会告诉 knockout 跟踪其中的每个对象和每个字段,这几乎不是我想要的。
现在,我终于让它工作了,但我的做法表明有一种更清洁的方法。
我发现,当您用它们重新声明数组时,可观察数组中的项目会以某种方式被跟踪并且不会更新。例如,我在问题中给出的代码不起作用。但是下面的代码有效:
var tmp_addresses = addresses();
var tmp_addr = tmp_addresses[0];
var new_addr = {};
Object.keys(tmp_addr).forEach(function(key){
new_addr[key] = tmp_addr[key];
});
new_addr.title = 'Hey this is something new!'
addresses.splice(0, 1, new_addr);
不满意?下面的代码也可以正常工作,因为我们正在重新定义数组:
var newAddressObject1 = {...}, newAddressObject2 = {...};
addresses([newAddressObject1, newAddressObject2]);
但以下行不通!
var tmp_addresses = addresses();
var tmp_addr = tmp_addresses[0];
tmp_addr.title = 'Hey this address wont update';
addresses.splice(0, 1, tmp_addr);
怎么会?我认为敲除在 observableArrays 中为他的项目添加了一个内部属性,当我尝试重新插入一个时,它不会更新。
我的问题现在已经演变为创建一个new 对象,该对象与可观察数组中所需项目的属性相同。我上面的编码方式看起来很脏。必须有更好的方法来做到这一点
【问题讨论】:
-
相信你的答案就在这里:stackoverflow.com/questions/14953248/…
-
观察的是数组,而不是单个元素。
-
@jason9187 我不是在更新单个元素,而是在更新整个数组。请查看我在问题中的更新
-
您的最后一个示例可能无法正常工作,因为您正在尝试拼接已在数组中的相同对象。 KO 可能不会将此解释为对数组的更改。
-
@jason9187 是的,这正是我所说的,ko 不会将其解释为一个新对象,尽管它的字段完全不同。所以我实际上正在考虑在调用
var tmp = addresses()时创建一个真正的新数组,例如new Array(addresses())
标签: javascript html knockout.js template-engine