そのため、タイトルは少し不自然ですが、これは本質的に私が達成したいことです:
<ul data-bind="template: { name: 'ItemFormTemplate', foreach: Items }">
@foreach (var item in Model.Items)
{
Html.RenderPartial("_ItemForm", item);
}
</ul>
<script type="text/html" id="ItemFormTemplate">
@{ Html.RenderPartial("_ItemForm", new Item()); }
</script>
ここでの考え方は次のとおりです。
のフォームを
Item
パーシャルにしたいのですが、Razor の foreach と Knockout へのテンプレートのフィードの両方に同じパーシャルを使用したいと考えています。(HTML を繰り返したり、Knockout のためだけに特別なバージョンを作成したりする必要はありません。)Razor foreach は、JavaScript が無効になっているかサポートされていない場合のフォールバック用です。フォームは、JavaScript の有無にかかわらず編集および送信可能である必要があります (モデル バインダーが POST データを正しく処理するように)。
これはもちろん、フィールド名が のようなパターンに従う必要があることを意味します
Items[0].SomeField
。Item
パーシャルは、(ではなく) 1 つだけに対して強く型付けされIEnumerable<Item>
ます。現在のインデックスはクライアント側でしか利用できないため、当然のことながら、これは Knockout テンプレートでは実際には不可能です。そのためにすでに使用している回避策があります。ko.bindingHandlers.prefixAndIndex = { init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) { if (bindingContext.$index) { var prefix = ko.utils.unwrapObservable(valueAccessor()); var $element = $(element); $element.find('input,textarea,select').each(function () { var $this = $(this); var newId = prefix + '_' + bindingContext.$index() + '__' + $this.attr('id'); var newName = prefix + '[' + bindingContext.$index() + '].' + $this.attr('name'); $('label[for=' + $this.attr('id') + ']').attr('for', newId); $this.attr('id', newId); $this.attr('name', newName); }); } } };
これは、テンプレートの最上位要素 (
<li>
この場合は ) にバインドし、すべての id および name 属性を検索して適切なプレフィックスに置き換えます。かなりうまくいっているようですが、改善のための批評や提案は大歓迎です。
本当に、私が今苦労しているのは、Razor foreach 内でパーシャルに適切なプレフィックスを取得することだけです。通常、for
代わりに を使用してこれを解決しforeach
、一般的なアイテムの代わりにインデックス付きのアイテムを渡します。つまり、次のようになります。
@for (var i = 0; i < Model.Items.Count(); i++)
{
@Html.TextBoxFor(m => m.Items[i].SomeField)
}
しかし、パーシャルを使用する場合、これは機能しません。なぜなら、パーシャルに入ると、Item
コンテキストから外れた単一の を扱っているだけだからです。
したがって、最も差し迫った問題は、部分的に強く型付けされた to を引き続き使用するにはどうすればよいかということItem
です。次に、それとは別に、重複や HTML とロジックを減らす (コードの再利用を増やす) 最善の方法について説明します。私は残りの考えで正しい軌道に乗っていますか?改善または改善できることはありますか?
編集
理想的には、部分的に強く型付けされたままにして、実際にそれを利用したいということを述べておく必要があります。@Html.TextBoxFor(m => m.SomeField)
つまり、ごまかすより、できるようになりたい@Html.TextBox("Items[" + iterator + "].SomeField")
。その道を行かなければならない場合、それは一つのことですが、もっと良い方法があることを願っています.
次のようなこともできると思います。
@Html.TextBox(prefix + "[" + iterator + "]." + Html.NameFor(m => m.SomeField))
そして、パーシャルに渡しprefix
ますiterator
。ハードコーディングされた値を処理する必要がないという意味では、これは優れていますが、特に多数のフィールドを持つパーシャルの場合は、多くの余分なロジックが発生します。繰り返しますが、より良い方法を期待しています。