我有一个简单的observableArray,它包含很多用户模型。 在标记中,有一个带有foreach循环的模板,循环用户并将它们输出到一个简单的表中。我还使用自定义滚动条和其他一些javascript来设置表格样式。所以现在我必须知道foreach循环何时完成并且所有模型都被添加到DOM中。
afterRender回调的问题在于每次添加内容时都会调用它,但我需要一种只触发一次的回调。
答案 0 :(得分:23)
您最好的选择是使用自定义绑定。您可以将foreach
后的自定义绑定放在data-bind
的绑定列表中,也可以在setTimeout
中执行代码以允许foreach
生成内容之前你的代码已被执行。
以下示例显示了每次observableArray更新时一次运行代码并运行代码:http://jsfiddle.net/rniemeyer/Ampng/
HTML:
<table data-bind="foreach: items, updateTableOnce: true">
<tr>
<td data-bind="text: id"></td>
<td data-bind="text: name"></td>
</tr>
</table>
<hr/>
<table data-bind="foreach: items, updateTableEachTimeItChanges: true">
<tr>
<td data-bind="text: id"></td>
<td data-bind="text: name"></td>
</tr>
</table>
<button data-bind="click: addItem">Add Item</button>
JS:
var getRandomColor = function() {
return 'rgb(' + (Math.floor(Math.random() * 256)) + ',' + (Math.floor(Math.random() * 256)) + ',' + (Math.floor(Math.random() * 256)) + ')';
};
ko.bindingHandlers.updateTableOnce = {
init: function(element) {
$(element).css("color", getRandomColor());
}
};
//this binding currently takes advantage of the fact that all bindings in a data-bind will be triggered together, so it can use the "foreach" dependencies
ko.bindingHandlers.updateTableEachTimeItChanges = {
update: function(element) {
$(element).css("color", getRandomColor());
}
};
var viewModel = {
items: ko.observableArray([
{ id: 1, name: "one" },
{ id: 1, name: "one" },
{ id: 1, name: "one" }
]),
addItem: function() {
this.items.push({ id: 0, name: "new" });
}
};
ko.applyBindings(viewModel);
答案 1 :(得分:9)
我想出了一个优雅的作弊。在模板/ foreach块之后,立即添加以下代码:
<!--ko foreach: { data: ['1'], afterRender: YourAfterRenderFunction } -->
<!--/ko-->
答案 2 :(得分:8)
一种快速而简单的方法是,在您的afterRender处理程序中,将当前项目与列表中的最后一项进行比较。如果匹配,则这是afterRender最后一次运行。
答案 3 :(得分:3)
Jaffa的回答中包含错误,所以我决定创建一个新答案而不是评论。无法同时使用with和模板。
因此,只需将模型移至模板data
标记
<强> HTML 强>
<div data-bind="template: {data: myModel, afterRender: onAfterRenderFunc }" >
<div data-bind="foreach: observableArrayItems">
...
</div>
</div>
<强>的Javascript 强>
var myModel = {
observableArrayItems : ko.observableArray(),
onAfterRenderFunc: function(){
console.log('onAfterRenderFunc')
}
}
ko.applyBinding(myModel);
答案 4 :(得分:1)
我不确定接受的答案是否适用于knockout-3.x(因为数据绑定不再按照您声明的顺序运行)。
这是另一种选择,它只会发射一次。
ko.bindingHandlers.mybinding {
init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
var foreach = allBindings().foreach,
subscription = foreach.subscribe(function (newValue) {
// do something here
subscription.dispose(); // dispose it if you want this to happen exactly once and never again.
});
}
}
答案 5 :(得分:0)
在我的头顶,您可以:
示例:
<div>
<div data-bind="with: parentItem(), template: { afterRender: myRenderFunc }" >
<div data-bind="foreach: observableArrayItems">
...
</div>
</div>
</div>
没有测试过,所以只是猜测...
答案 6 :(得分:0)
为了找出foreach模板何时完成渲染,您可以进行“虚拟”绑定,并将当前渲染的项目索引传递给处理程序,并检查它是否与数组长度匹配。
<强> HTML:强>
<ul data-bind="foreach: list">
<li>
\\ <!-- Your foreach template here -->
<div data-bind="if: $root.listLoaded($index())"></div>
</li>
</ul>
ViewModel - 处理程序:
this.listLoaded = function(index){
if(index === list().length - 1)
console.log("this is the last item");
}
如果您打算在列表中添加更多项目,请保留额外标记。
答案 7 :(得分:0)
如何使用去抖动器?
var afterRender = _.debounce(function(){
// code that should only fire 50ms after all the calls to it have stopped
}, 50, { leading: false, trailing: true})