Knockout のほとんどは非常に直感的です。私にとって奇妙なことの 1 つは、マッピング プラグインの仕組みです。私は、ajax 呼び出しから JSON をフィードし、HTML で参照できる一種の「動的」ビュー モデルを使用できることを期待/期待していました。
マッピングプラグインの説明は、次のように聞こえます。
「データ構造がより複雑になると (たとえば、子が含まれたり、配列が含まれたりすると)、手動で処理するのが非常に面倒になります。マッピング プラグインを使用すると、通常の JavaScript オブジェクト (または JSON 構造) からオブザーバブルへのマッピングを作成できます。モデルを表示します。」
しかし、実際にはコードで最初にビュー モデルを定義する必要があるようです。その後、マッピング プラグインといくつかの JSON データを使用して、後でビュー モデルを設定できます。これは正しいですか?
私がやろうとしていたことの具体例。
Solr (JSON 検索結果を返す検索エンジン) で Knockout を使用しようとしています。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 配列にはハッシュの配列が含まれており、ハッシュ データはインデックス付けされたドキュメント データのキー/値で構成されています。配列内の各ハッシュは、検索結果で返される 1 つのドキュメントです。
その部分はうまくマッピングされているようです。
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"]
}
}
各 response.docs 要素を解析しようとする HTML に foreach があり、オブジェクトの強調表示部分にそのドキュメントの Id フィールドとの一致が含まれている場合、デフォルトのタイトルではなく、強調表示されたタイトルに置き換えたいと考えています。(以下のコードでは、「Results」は、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 で問題を再現できません。:-(
編集OK 私はここでいくらか前進していますが、何が起こっているのかまだ非常に混乱しています。まず、デバッグ 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 をループしており、最初の 2 つはハイライト() オブジェクトの何にもマッピングされていないため、未定義を返しています。プロパティは失敗していました。
これを確認するために、ko if: $root.Results.highlighting()[Id()]
そのブロックを a で囲み、最終的に foreach ループ中に .Title プロパティに JS エラーなしでアクセスできました。
これにより、なぜ/どのように 3 つの Results.response.docs オブジェクトがループされているのかという疑問が残ります。おそらく foreach バインディングが 3 回実行され、最初の 2 回は強調表示オブジェクトが空で、3 回目は最終的に入力されているのでしょうか? しかし、私はそれがなぜなのかを理解するのに苦労しています。
もう 1 つの考えられる手がかり: ページをリロードせずに 2 回目の ajax 呼び出しをトリガーすると、これら 3 つの「パス」がすべて、コンソール ログで毎回有効なオブジェクトを返すことがわかります。したがって、2 つundefined
の と 1 つのオブジェクトの代わりに、3 つのオブジェクトがすべて並んでいます。
ただし、HTML 出力では、1 行のデータしか表示されません。これは、3 つの要素をループしているのではなく、実際には 3 回実行されていることを証明しているようです。問題は残ります...なぜですか?