大多数 Knockout 看起来非常直观。对我来说奇怪的一件事是映射插件的工作原理。我期待/希望我能够从 ajax 调用中为其提供 JSON,并拥有一种可在我的 HTML 中引用的“动态”视图模型。
映射插件的描述甚至听起来像是它的工作原理:
“如果您的数据结构变得更加复杂(例如,它们包含子对象或包含数组),手动处理会变得非常麻烦。映射插件允许您创建从常规 JavaScript 对象(或 JSON 结构)到可观察对象的映射查看模型。”
但看起来您实际上需要首先在代码中定义视图模型,然后您可以在事后使用映射插件和一些 JSON 数据来填充它。这是正确的吗?
我试图做的一个具体例子。
我正在尝试将 Knockout 与 Solr(返回 JSON 搜索结果的搜索引擎)一起使用。Solr 返回的 JSON 数据的骨架结构为:
{
"responseHeader": {
"status": 0,
"QTime": 0,
"params": {
"facet": "true",
"facet.field": "System",
"q": "testphrase",
"rows": "1",
"version": "2.2"
}
},
"response": {
"numFound": 0,
"start": 0,
"maxScore": 0.0,
"docs": []
},
"facet_counts": {
"facet_queries": {},
"facet_fields": {
"System": []
},
"facet_dates": {},
"facet_ranges": {}
},
"highlighting": {}
}
事实上,这就是我第一次设置映射视图模型时输入的结构。
只是为了让您了解一些关于 JSON 数据如何从 Solr 返回的信息: response.docs 数组包含一个哈希数组,其中哈希数据由索引文档数据的键/值组成。数组中的每个哈希都是在搜索结果中返回的一个文档。
那部分似乎映射得很好。
JSON 的“突出显示”部分是导致我出现问题的原因。当我尝试在我的 HTML 中引用突出显示的字段时,我得到了 ReferenceErrors。以下是 JSON 中突出显示字段的示例:
"highlighting": {
"2-33-200": {
"Title": ["1992 <b>Toyota</b> Camry 2.2L CV Boots"]
},
"2-28-340": {
"Title": ["2003 <b>Toyota</b> Matrix 2.0L Alignment"]
},
"2-31-2042": {
"Title": ["1988 <b>Toyota</b> Pickup 2.4L Engine"]
}
}
我的 HTML 中有一个 foreach 尝试解析每个 response.docs 元素,如果对象的突出显示部分包含与该文档的 Id 字段匹配的内容,我想替换突出显示的标题而不是默认标题。(在下面的代码中,“结果”是我将 JSON 映射到的视图模型的名称。)
<div id="search-results" data-bind="foreach: Results.response.docs">
<div data-bind="attr: { id: 'sr-' + Id }" class="search-result">
<h3 class="title"><a data-bind="html: (($root.Results.highlighting[Id]['Title'] != undefined) ? $root.Results.highlighting[Id]['Title'] : Title), attr: {href: Link}"></a></h3>
<span class="date" data-bind="text: DateCreated"></span>
<span class="snippet" data-bind="html: Snippet"></span>
</div>
</div>
当我尝试使用它时,我总是收到此错误:
Uncaught Error: Unable to parse bindings.
Message: TypeError: Cannot read property 'Title' of undefined;
Bindings value: html: (($root.Results.highlighting[Id]['Title'] != undefined) ? $root.Results.highlighting[Id]['Title'] : Title), attr: {href: Link}
我已经尝试过如何引用数据的变化,但我似乎无法访问它。
编辑我正在取得一些进展。在我的映射定义中,我现在指定“突出显示”,如下所示:
"highlighting": ko.observable({})
而不仅仅是将突出显示设置为 {}。现在,当我进行映射时,我至少能够稍微查看一下突出显示的数据。然而,我仍然看到奇怪的错误。
我已经简化了我的测试 HTML 代码,只为每个搜索结果吐出突出显示的数据:
<div id="search-results" data-bind="foreach: Results.response.docs">
<pre data-bind="text: JSON.stringify(ko.toJS($root.Results.highlighting()[Id()]), null, 2)"></pre>
</div>
现在返回多个<pre>
标签,如下所示:
{
"Title": [
"1992 <b>Toyota</b> Camry 2.2L CV Boots"
]
}
但是,如果我将该 HTML 代码更改为:
<pre data-bind="text: $root.Results.highlighting()[Id()]['Title']"></pre>
我继续收到这样的错误:
Message: TypeError: Cannot read property 'Title' of undefined;
Bindings value: text: $root.Results.highlighting()[Id()]['Title']
对我来说毫无意义!我之前的测试表明,可用的数据确实包含“标题”键,为什么我不能访问该数据?
编辑我创建了一个 jsfiddle,但当然......它按预期工作。我无法在 jsfiddle 上重现我的问题。:-(
编辑好吧,我在这里取得了一些进展,但我仍然对发生的事情感到非常困惑。首先,我将调试 HTML 更改为:
<div id="search-results" data-bind="foreach: Results.response.docs">
<pre data-bind="text: console.log($root.Results.highlighting()[Id()])"></pre>
</div>
然后我提交了我的 ajax 调用,我在 Chrome 控制台中注意到了这个输出:
undefined
undefined
> Object
因此,由于某种原因,foreach
循环在 3 个 Results.response.docs 上循环,前两个没有映射到我的 highlight() 对象中的任何内容,所以它们返回未定义——这就是我尝试拉 .Title 的原因财产失败。
为了确认这一点,我ko if: $root.Results.highlighting()[Id()]
在该块周围包裹了一个,最终能够在 foreach 循环期间访问 .Title 属性,而不会出现 JS 错误。
这仍然给我留下了为什么/如何有 3 个 Results.response.docs 对象被循环的问题。也许 foreach 绑定正在运行 3 次,前 2 次突出显示对象是空的,第三次,它终于被填充了?但我很难弄清楚为什么会这样。
另一个可能的线索:如果我第二次触发 ajax 调用,而不重新加载页面,我可以看到这 3 个“通过”每次都在控制台日志中返回一个有效的对象。所以不是两个undefined
s 和一个 Object ,而是三个 Object 都排成一行。
但是,在我的 HTML 输出中,我只看到一行数据。所以这似乎证明它不是循环超过 3 个元素,而是实际上运行了 3 次。问题仍然存在……为什么?