Ciarán Bruen
Ciarán Bruen

Reputation: 5341

ASP.NET MVC 3 - bind multiple instances of the same field in knockout

How can I get knockout bound to multiple instances of the same input fields? I have an Editor Template that renders 7 normal input fields in a hidden div, then I use jQuery .after() to display them in the position I want:
Editor Template:

@model ProductRepAttributeViewModel
@{
    // Get the prefix and use it for the knockout field names
    var htmlFieldPrefix = ViewData.TemplateInfo.HtmlFieldPrefix;

    var idx1 = htmlFieldPrefix.IndexOf("Products", StringComparison.Ordinal);
    var koProductPrefix = htmlFieldPrefix.Insert(idx1 + "Products".Length, "()");

    var idx2 = koProductPrefix.IndexOf("ProductRepAttributes", StringComparison.Ordinal);
    var koPrefix = koProductPrefix.Insert(idx2 + "ProductRepAttributes".Length, "()");

    var dictTextBoxAttrs = new Dictionary<string, object>
    {
        { "style", "width: 80%;" },
        { "data-bind", string.Format("value: currentBatch.{0}.Value", koPrefix) }
    };
}
<div class="Expressed" style="width: 10%; display: block; float: left;">
    @Html.TextBoxFor( model => model.Value, dictTextBoxAttrs )
    @Html.ValidationMessageFor(model => model.Value)
</div>

jQuery:

$('.expressed-container').after($('.Expressed'));

Razor:

<div style="display: none">
    @Html.EditorFor(x => x.ProductRepAttribute)
</div>

<div style="padding-top: 20px; padding-bottom: 20px" class="grid_12">
<div style="width: 8%; display: block; float: left;">
    @Html.Label("Start", labelStyleDict)
</div>
<div class ="encoded-container"></div>
<div style="width: 10%; display: block; float: left;">
    @Html.Label("End", labelStyleDict)
</div>
</div>

Rendered Html:

<input type="text" value="" style="width: 80%;" name="Products[0].ProductRepAttributes[0].Value" id="Products_0__ProductRepAttributes_0__Value" data-bind="value: currentBatch.Products()[0].ProductRepAttributes()[0].Value">
<!-- 6 more fields indexed 1 to 6 -->

All fine and dandy - the fields appear after my "encoded-container" div and are named correctly and bound to knockout. Now I need to display the same fields in a different tab, so when one field gets updated the equivalent one on the other tab should also be updated.
I copied and pasted the Razor code (without the EditorFor call) into the second tab and the fields appear fine and have the same names/ids as the original set (although I know fields are supposed to have unique ids), however only the last rendered set of fields are bound to knockout. How do I bind both sets of fields? I've also tried using jQuery clone(), .insertAfter(), and appendTo() to try and clone or copy the fields but none of these work.

I could use a Partial View instead of an Editor Template but that would involve manually writing the code for all 7 fields, which I don't want to do. The Editor Template solution is neat and works well so I'd like to keep using it.

Upvotes: 0

Views: 472

Answers (1)

Ciar&#225;n Bruen
Ciar&#225;n Bruen

Reputation: 5341

Ok found the problem - spent an hour writing the question then solved it in 5 minutes! Firstly in jQuery I used appendTo() instead of after(). This didn't fix the problem but then I realised I was calling appendTo() after initialising my knockout model, which meant there was only one set of fields for knockout to bind to. So running appendTo() before I bound the model meant that the multiple fields are in place, so knockout finds them and binds them correctly.

Lesson learned - if it's ok I can leave the question here for anyone that might have a similar issue.

Upvotes: 1

Related Questions