Here is the problem that I am facing and not sure how to even approach it:
I created models, controllers and views in ASP.NET MVC 4. At one point I had to create dynamic lists, so I opted out to KnockoutJS, what solves this problem extremely easy. So far so good. Then I realized that the validation I defined on my MVC models using I use Fluent Validation doesn't work anymore in the knockout view.
I searched through SO and found few viable solutions:
- knockout validation
- jquery validation
- potentially express Knockout syntax in terms of razor
I tend to use the latter one, for several reasons. Mainly because it gives me opportunity not to introduce (learn, test, localize, spend time) another library.
I am quite familiar with MVC and love the way it supports localization giving full control on messages, labels etc. I also love Fluent Validation and don't want to replace it with others (more static, much harder to localize, much less flexible to my liking)
I found some examples on knockout to razor conversion, when data-bind has to become data_bind etc.
I cannot find a way to express the foreach loop with and in.
MVC view model
public class ContactEmail
{
public string SelectedLabel { get; set; }
public string Name { get; set; }
}
public class User
{
public IList<ContactEmail> Emails { get; set; }
}
ViewBag.EmailLabels = new string[] { "label1", "label2", ... };
knockout model
var viewModel = {
EmailLabels: ko.observableArray(@Html.Json(ViewBag.EmailLabels as string[]) || []),
Emails: ko.observableArray(@Html.Json(@Model.Emails) || []),
}
knockout view (that I wanted to transform)
<table>
<tbody data-bind="foreach: Emails">
<tr>
<td>
@* How to make razor below work instead of knockout syntax below it? *@
@*Html.DropDownListFor(m => ????, new { data_bind="options: $root.EmailLabels, value: SelectedLabel, optionsCaption: 'Choose...'" } )
<select data-bind="options: $root.EmailLabels, value: SelectedLabel, optionsCaption: 'Choose...'"></select></td>
<td>
@* How to make razor below work as well instead of knockout syntax below ?!?!? *@
@Html.TextBoxFor(m => ????, new { data_bind="value: Name, uniqueName: true" } )
<input type="text" data-bind="value: Name, uniqueName: true" class="required email" />
</td>
<td>
<a href="#" data-bind="click: function() { viewModel.removeEmail(this); }">Delete</a>
</td>
</tr>
</tbody>
</table>
I looked at MVC Controls toolkit what one guy mercilessly advertised will solve all my validation and localization and everything at all. I found it unusable, very proprietary and extremely hard to understand. Its like buying nuke to kill a bird.
So please those of you who had experience with marrying MVC with knockout, please step up and share your experience.
Any help will be greatly appreciated & thank you very much in advance.
I think this is a bit of a hack, but it works.
The controller will return a collection of emails inside of the User.Emails property with the list that need to be rendered. What the Razor View produces is HTML of a table with just one row and the validation based off the first element of the Emails IEnumerable (this must be checked for null or may cause an exception).
When ko.applyBindings() occur on the client side, then the foreach on the tbody tag will produce all rows, and since the ko ViewModel as initialized with the whole collection as a mapped JsonString, then the whole list will render. The methods removeEmail and addEmail will work as well (I just tested the removeEmail option, it works =D)
Edit: Update to include definitive Knockout Bindings
index.cshtml
** Models (with validation working) **