【问题标题】:knockout foreach nested in a with嵌套在 with 中的淘汰赛 foreach
【发布时间】:2026-02-09 15:45:01
【问题描述】:

我想用 ko 绑定一个简单的结构,但在绑定过程中出现异常。 我的虚拟机如下所示:

function VM() {
    this["longNameObjId1"] = new Object();
    this["longNameObjId1"].records = ko.observableArray();

    var obj1 = new Object();
    obj1.L1 = "a";
    obj1.L2 = "b";
    obj1.L3 = "c";
    this["longNameObjId1"].records.push(obj1);

    var obj2 = new Object();
    obj2.L1 = "A";
    obj2.L2 = "B";
    obj2.L3 = "C";

    this["longNameObjId1"].records.push(obj2)            
}

我正在尝试遍历 longNameObjId1 属性的 records 数组中的所有对象并将它们放在一个表中。我确实需要对记录数组的更改进行一些控制,所以我开始包装 foreach 流控制,如下所示:

ko.bindingHandlers.dynCollection = {
    init: function (element, valueAccessor, allBindingsAccessor, viewModel, context){                
        ko.bindingHandlers.foreach.init(element, valueAccessor, allBindingsAccessor, viewModel, context);
    },
    update: function (element, valueAccessor, allBindingsAccessor, viewModel, context) {                
        ko.bindingHandlers.foreach.update(element, valueAccessor, allBindingsAccessor, viewModel, context);                
    }
};

没什么特别的。在视图方面,我认为应该这样做:

<!-- ko with: longNameObjId1 -->
<table>
    <thead>
        <tr>
            <th style="width: 33%">L1</th>
            <th style="width: 25%">L2</th>
            <th style="width: 25%">L3</th>
            <th style="width: 17%"></th>
            <th></th>
        </tr>
    </thead>
    <tbody id="test_tBody" data-bind="dynCollection: records">
        <tr>
            <td id="test_td1" data-bind="text: L1"></td>
            <td id="test_td2" data-bind="text: L2"></td>
            <td id="test_td3" data-bind="text: L3"></td>
        </tr>
    </tbody>
</table>
<!-- /ko -->

在运行时,我可以在浏览器中看到带有预期数据的表格。我遇到的问题是我收到如下异常:

Error: Unable to parse bindings.
Message: ReferenceError: L1 is not defined;
Bindings value: text: L1

我很乐意忽略这个错误,因为我可以在浏览器中看到我的数据,但问题是 records 数组并没有真正绑定:例如调用 push() 从控制台显示表格后(并忽略错误)不会触发 dynCollection.update() 函数。

有人能指出我的错误在哪里,或者可能是映射 records 数组的更好方法吗?

我在 Windows Server 2008 R2 SP1 上使用带有 FF 20.0 的淘汰赛 2.2.1。

如果您需要更多详细信息,请告诉我。
谢谢,
弗洛。

更新
在我尝试过的一些事情中,像这样使用上下文属性 $data

<td id="test_td1" data-bind="text: $data.L1"></td>

这变成了一个相当意外的行为:错误不再表现出来,但我的表也没有表现出来:我的页面中有一个空表,但没有错误。必须有一些我绝对不了解绑定的东西。如果有人能对这种特殊行为有所了解,我将不胜感激。谢谢。

【问题讨论】:

  • dynCollection 完全是多余的,为什么不直接使用 foreach 绑定呢?
  • 我需要捕获对此集合的所有更改,无论是用户操作还是服务器通知,并在客户端执行其他任务。包装 foreach 绑定只是第一步。
  • 好吧,想一想,如果它只有逻辑而没有 UI,它更适合作为可观察的扩展器。自定义处理程序用于 VM UI 绑定
  • 感谢您的提示。我将检查可观察的扩展器,因为我还将有大量数据将进入 d3。

标签: javascript knockout.js foreach with-statement


【解决方案1】:

只需在 foreach.init 子调用之前添加 return

init: function (element, valueAccessor, allBindingsAccessor, viewModel, context){                
    return ko.bindingHandlers.foreach.init(element, valueAccessor, allBindingsAccessor, viewModel, context);
},

这会在 records 未初始化时停止表格行模板化。

【讨论】:

  • 澄清一下,它的作用是返回 { controlsDescendantBindings: true } 这将使 KO 明白绑定呈现的 html 不应受当前上下文的约束,而是应受绑定定义的上下文的约束处理程序