ASP.NET with knockout variable length list with combobox - how to link?

With the following ASP.NET models

public class User { public string Name { get; set; } public LEmail LEmail { get; set; } } public class LEmail { public IList<CLabel> Labels; public IList<CEmail> Emails; } public class CLabels { public IList<CLabel> Labels { get; set; } } public class CLabel { public string Name { get; set; } } public abstract class CEmail { public string SelectedLabel { get; set; } public string Name { get; set; } } 

Filling this with dummy data and sending the corresponding view as a User object, I have the following knockout definitions in the view:

 @using (Html.BeginForm("MyAction", "MyController", FormMethod.Post, new { id = "MyEditor" })) { @Html.EditorFor(m => @Model.LEmail) <p> <input type="submit" value="Save" data-bind="enable: Emails().length > 0" /> <a href="/">Cancel</a> </p> <p data-bind="visible: saveFailed" class="error">A problem occurred saving the data.</p> <div id="debug" style="clear: both"> <hr /> <h2>Debug:</h2> <div data-bind="text: ko.toJSON(viewModel)"></div> </div> } <script type="text/javascript"> $(function() { ko.applyBindings(viewModel); $("#profileEditorForm").validate({ submitHandler: function(form) { if (viewModel.save()) window.location.href = "/"; return false; } }); }); var viewModel = { Name: ko.observable("@Model.Name"), Labels: ko.observableArray(@Html.Json(Model.LEmail.Labels) || []), Emails: ko.observableArray(@Html.Json(Model.LEmail.Emails) || []), addEmail: function() { viewModel.Emails.push(@Html.Json(new CEmail())); }, removeEmail: function(eml) { viewModel.Emails.remove(eml); }, saveFailed: ko.observable(false), // Returns true if successful save: function() { var saveSuccess = false; viewModel.saveFailed(false); // Executed synchronously for simplicity jQuery.ajax({ type: "POST", url: "@Url.Action("MyAction", "MyController")", data: ko.toJSON(viewModel), dataType: "json", contentType: "application/json", success: function(returnedData) { saveSuccess = returnedData.Success || false; viewModel.saveFailed(!saveSuccess); }, async: false }); return saveSuccess; } }; </script> 

And finally, the editor template, which should actually take care of a variable-length list, looks like this:

 @model MyDomain.ViewModels.LEmail <table> <tbody data-bind="template: { name: 'EmailsTemplate', foreach: Emails }" /> </table> <button data-bind="click: addEmail">Add Email</button> <script id="EmailsTemplate" type="text/html"> <tr> <td> @* PROBLEM IS HERE!! Labels won't show (they will it this code taken out of template) *@ <select data-bind="options: Labels"></select></td> <td> <input type="text" data-bind="value: Name, uniqueName: true" class="required" /></td> <td> <a href="#" data-bind="click: function() { viewModel.removeEmail(this); }">Delete</a></td> </tr> </script> 

Essentially I

  • can't make it work in EditorTemplate for combobox (or drop down list). It will not be attached to labels no matter what I do. If I take it out of the template somewhere else - it works as expected.
  • Also, based on the choice to populate the "SelectedValue" inside the email - how to do it.

  • After everything is selected (it should be simple), how to publish it all back without losing value (its super-nested model, as you can see).

Thank you in advance!

0
source share
1 answer

Labels are located on your view model, and not on each email. Since the template is rendered in the context of the foreach knockout binding, the binding context has changed to email.

Here's how I write your opinion:

 @model FiveW.ViewModels.LabeledEmail <table> <tbody data-bind="foreach: Emails"> <tr> <td> <select data-bind="options: $root.Labels, value: SelectedLabel"></select> </td> <td> <input type="text" data-bind="value: Name, uniqueName: true" class="required" /> </td> <td> <a href="#" data-bind="click: function() { viewModel.removeEmail(this); }">Delete</a> </td> </tr> </tbody> </table> <button data-bind="click: addEmail">Add Labeled Email</button> 

Correction in $ root.Labels: we need to tell Knockout to use $ root (your view model), since the shortcuts are actually on your view model, and not on a separate message.

Also note that I did not use a named template. This is preferable. If you do not use the template in several places in your view, you should use anonymous built-in templates, as I did above.

+1
source

All Articles