Can a JavaScript variable from a knockout call be mapped or assigned to a MVC3 view model variable, i.e., MVC3 view model variable = javascript knockout value?

3,263 views
Skip to first unread message

stevess...@gmail.com

unread,
Dec 31, 2011, 4:10:05 PM12/31/11
to knock...@googlegroups.com

I’ve seen this question asked by less experienced MVC3/Knockout programmers like myself but I haven’t come across anyone answering the question.  The question might be off base but it would be nice to know how things should be handled.  If you are not working with MVC3 then you may not understand where this question originates from.

In MVC3 I have a complex view model that I pass from my controller to the view.  When creating the view I specify Razor (CSHTML) as the view engine, a strongly typed view, and the model class.  This places a “@model MyApp.ViewModels.MyComplexModelClass” statement in the view.

Within my HTML form a typical mapping to a MVC3 view model field would then be like the following. 

        <div class="editor-field">

            @Html.EditorFor(model => model.Country)

            @Html.ValidationMessageFor(model => model.Country)

        </div>

 

Normally when everything is filled out on my HTML form I simply call “submit” and Razor passes my MVC3 view model back to the controller where I can process the user’s responses.

Everything is cool until I want to do a Knockout/JavaScript lookup for a select list. To do this I create a JavaScript view model, bind the appropriate variables, and call a lookup action on the controller.  I can see my value coming back in debugger but I am unable to assign it to the appropriate MVC3 view model variable. 

In examples I have seen others approach this problem by converting the whole MVC3 view model to a JavaScript view model, manually bind the fields, and then pass the JavaScript/JSON view model back to the controller when the form is complete.  The problem with this is that it seems like a lot of manual work, it may not work with my complex MVC3 view model, my data annotations would cease to function [@Html.ValidationMessageFor(model => model.Country)], etc.

Can a JavaScript variable from a knockout call be mapped or assigned to a MVC3 view model variable, i.e., MVC3 view model variable = javascript knockout value?  Can Knockout be implemented with MVC3 view models?

The Sample code below is from a project I pulled together to isolate this problem in my application.  Note that in the code section starting with "this.muncipalityCd.subscribe(function (municipalityCd) {" is where I am trying to set the MVC3 view model variable.   Also, at the end of the sample there is another possible approach that I have listed.

Thank you for any guidance you can give while approaching this scenario.

Sample

@model KiltR.ViewModels.Residency

 

@{

    ViewBag.Title = "MVC Knockout Example";

}

 

@*<h2>Index</h2>*@

 

<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>

<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>

 

<script type="text/html" id="noInfoTemplate">

        No Information Available (Select State, County, and then Municipality)

</script>

 

<script type='text/javascript'>

    $(document).ready(function () {

//        var initialData = @Html.Raw( new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(Model));

        var residencyItems = function () {

            this.residencyStateCd = ko.observable();

            this.countyCd = ko.observable();

            this.muncipalityCd = ko.observable();

            this.schoolDistictCd = ko.observable();

            this.states = ko.observableArray();

            this.counties = ko.observableArray();

            this.municipalities = ko.observableArray();

            this.schoolDistricts = ko.observableArray();

            this.residencyServerModel = ko.observable(initialData);

 

            var selectedStateCd = undefined;

            var selectedCountyCd = undefined;

            var selectedMunicipalityCd = undefined;

            var selectedSchoolDistrictCd = undefined;

 

            // Whenever the state changes, reset the county selection

            this.residencyStateCd.subscribe(function (stateCd) {

                selectedStateCd = stateCd;

                initialData.ResidencyStateCd = stateCd;

                this.countyCd(undefined);

                this.counties(undefined);

 

                if (stateCd != null) {

                    $.ajax({

                        url: '@Url.Action( "GetCounties", "MVCKnockout")',

                        data: { stateCd: stateCd },

                        type: 'GET',

                        success: function (data) {

                            residencyViewModel.counties(data);

                        }

                    });

                }

            } .bind(this));

 

            // Whenever the county changes, reset the municipality selection

            this.countyCd.subscribe(function (countyCd) {

                selectedCountyCd = countyCd;

                initialData.CountyCd = countyCd;

                this.muncipalityCd(undefined);

                this.municipalities(undefined);

                if (countyCd != null) {

                    $.ajax({

                        url: '@Url.Action( "GetMunicipalities", "MVCKnockout")',

                        data: { stateCd: selectedStateCd, countyCd: countyCd },

                        type: 'GET',

                        success: function (data) {

                            residencyViewModel.municipalities(data);

                        }

                    });

                }

            } .bind(this));

 

            // Whenever the municipality changes, reset the school district selection

            this.muncipalityCd.subscribe(function (municipalityCd) {

                selectedMunicipalityCd = municipalityCd;

                initialData.MunicipalityCd = municipalityCd;

                this.schoolDistictCd(undefined);

                this.schoolDistricts(undefined);

 

                if (municipalityCd != null) {

                    $.ajax({

                        url: '@Url.Action( "GetSchoolDistricts", "MVCKnockout")',

                        data: { stateCd: selectedStateCd, countyCd: selectedCountyCd, municipalityCd: municipalityCd },

                        type: 'GET',

                        success: function (data) {

                        if(data) {

                            residencyViewModel.schoolDistricts(data);

                            // This is where I am attempting to set my MVC3 view model i.e., replace the JS var fields with the MVC view model fields

                            var tempCd = data[0].SchoolDistrictCd; //This works...

                            var tempDescr = data[0].SchoolDistrictDescr; //This works...

                            @("Residency.SchoolDistrictCd") = tempCd;  //This does not work....

                            }

                        }

                    });

                }

            } .bind(this));

        };

 

        var residencyViewModel = new residencyItems();

        ko.applyBindings(residencyViewModel);

 

        //Load the states

        $.ajax({

            url: '@Url.Action( "GetResidencyStates", "MVCKnockout" )',

            type: 'GET',

            success: function (data) {

                residencyViewModel.states(data);

            }

        });

    });

</script>

@using (Html.BeginForm()) {

    @Html.ValidationSummary(true)

    <fieldset>

        <legend>Residency</legend>

 

        <div class="editor-label">

            @Html.LabelFor(model => model.Country)

        </div>

        <div class="editor-field">

            @Html.EditorFor(model => model.Country)

            @Html.ValidationMessageFor(model => model.Country)

        </div>

 

        <div class="editor-label">

            <span class="error">*</span>@Html.LabelFor(m => m.ResidencyStateCd)

        </div>

        <div class="editor-field">

            <select id='states'

                                data-bind='

                                        options: states,

                                        optionsValue : "ResidencyStateCd",

                                        optionsText: "ResidencyStateDescr",

                                        optionsCaption: "[Please select a state]",

                                        value: residencyStateCd'>

            </select>

        </div>

            <div class="editor-label">

                <span class="error">*</span>@Html.LabelFor(m => m.CountyCd)

            </div>

            <div class="editor-field">

                <select id='counties'

                                        data-bind='

                                                options: residencyStateCd() ? counties : null,

                                                optionsValue : "CountyCd",

                                                optionsText: "CountyDescr",

                                                optionsCaption: "[Please select a county]",

                                                value: countyCd,

                                                visible: (counties() && counties().length > 0 )'>

                </select>

                <span data-bind='

                                template: {name: "noInfoTemplate"},

                                visible: !(counties() && counties().length > 0)'>

                        </span>

            </div>

            <div class="editor-label">

                <span class="error">*</span>@Html.LabelFor(m => m.MuncipalityCd)

            </div>

            <div class="editor-field">

                <select id='municipalities'

                                        data-bind='

                                                options: countyCd() ? municipalities : null,

                                                optionsValue : "MunicipalityCd",

                                                optionsText: "MunicipalityDescr",

                                                optionsCaption: "[Please select a municipality]",

                                                value: muncipalityCd,

                                                visible: (municipalities() && municipalities().length > 0 )'>

                </select>

                <span data-bind='

                                template: {name: "noInfoTemplate"},

                                visible: !(municipalities() && municipalities().length > 0)'>

                        </span>

            </div>

            <div class="editor-label">

                <span class="error">*</span>@Html.LabelFor(m => m.SchoolDistrictCd)

            </div>

            <div class="editor-field">

                <select id='schoolDistricts'

                                        data-bind='

                                                options: muncipalityCd() ? schoolDistricts : null,

                                                optionsValue : "SchoolDistrictCd", @*ScSclDistCd", *@

                                                optionsText: "SchoolDistrictDescr",

                                                optionsCaption: "[Please select a school district]",

                                                value: schoolDistictCd,

                                                visible: (schoolDistricts() && schoolDistricts().length > 0 )'>

                </select>

                <span data-bind='

                                template: {name: "noInfoTemplate"},

                                visible: !(schoolDistricts() && schoolDistricts().length > 0)'>

                        </span>

            </div>

        <p>

            <input type="submit" value="Create" />

        </p>

    </fieldset>

}

 

<div>

    @Html.ActionLink("Back to List", "Index")

</div>

 

 

Maybe I am trying to set the value in the wrong place.  Perhaps I should be trying to use the Razor syntax to call the Knockout/ JavaScript code something like the following:

@Html.DropDownListFor(model => model.ResidencyStateCd, new SelectList(Enumerable.Empty<SelectListItem>(), "ResidencyStateCd", "Residency"),

"Please select a state", new { id = "states" })

 

Rather than this from the sample above:

        <div class="editor-field">

            <select id='states'

                                data-bind='

                                        options: states,

                                        optionsValue : "ResidencyStateCd",

                                        optionsText: "ResidencyStateDescr",

                                        optionsCaption: "[Please select a state]",

                                        value: residencyStateCd'>

            </select>

        </div>

 

Note that I found the above syntax in another example and I have not tried to wire it up to my Knockout /Ajax logic.

Weej

unread,
Jan 1, 2012, 9:41:25 AM1/1/12
to KnockoutJS
Hi Steve,

I'm about 1 or 2 steps ahead of you on this, so I can see where you're
comming from. The important thing to realize about Razor or the
earlier MVC markup is that it gets executed at the server. KO gets
executed on the client. Two different time frames and states. Razor
will never be able to call KO code directly unless Razor renders
script that will call KO. KO also can not call stuff in Razor Tokens
for the same reason: They don't share the same dimension of
existance. When one is active the other isn't.

@("Residency.SchoolDistrictCd") = tempCd; //This does not
work....

You won't find any Razor code in the browser's HTML or Script tags
because the page rendering engine at the server will have converted
it. Your Ajax call just sends data back from the server, not a re-
rendering of the .Ajax function.

So... how do you get your data into your page? You poke it into the
html element and get it back to the server in your form submission.
You can use straight JavaScript or jQuery to get it there in your Ajax
success: call back.

I hope this helps...
> *Can a JavaScript variable from a knockout call be mapped or assigned to a
> MVC3 view model variable, i.e., MVC3 view model variable = javascript
> knockout value?  Can Knockout be implemented with MVC3 view models?*
>
> The Sample code below is from a project I pulled together to isolate this
> problem in my application.  Note that in the code section starting with "
> this.muncipalityCd.subscribe(function (municipalityCd) {" is where I am
> trying to set the MVC3 view model variable.   Also, at the end of the
> sample there is another possible approach that I have listed.
>
> Thank you for any guidance you can give while approaching this scenario.
>
> *Sample*
>                         url: '...@Url.Action( "GetCounties", "MVCKnockout")',
>
>                         data: { stateCd: stateCd },
>
>                         type: 'GET',
>
>                         success: function (data) {
>
>                             residencyViewModel.counties(data);
>
>                         }
>
>                     });
>
>                 }
>
>             } .bind(this));
>
>             // Whenever the county changes, reset the municipality selection
>
>             this.countyCd.subscribe(function (countyCd) {
>
>                 selectedCountyCd = countyCd;
>
>                 initialData.CountyCd = countyCd;
>
>                 this.muncipalityCd(undefined);
>
>                 this.municipalities(undefined);
>
>                 if (countyCd != null) {
>
>                     $.ajax({
>
>                         url: '...@Url.Action( "GetMunicipalities",
> "MVCKnockout")',
>
>                         data: { stateCd: selectedStateCd, countyCd:
> countyCd },
>
>                         type: 'GET',
>
>                         success: function (data) {
>
>                             residencyViewModel.municipalities(data);
>
>                         }
>
>                     });
>
>                 }
>
>             } .bind(this));
>
>             // Whenever the municipality changes, reset the school district
> selection
>
>             this.muncipalityCd.subscribe(function (municipalityCd) {
>
>                 selectedMunicipalityCd = municipalityCd;
>
>                 initialData.MunicipalityCd = municipalityCd;
>
>                 this.schoolDistictCd(undefined);
>
>                 this.schoolDistricts(undefined);
>
>                 if (municipalityCd != null) {
>
>                     $.ajax({
>
>                         url: '...@Url.Action( "GetSchoolDistricts",
> "MVCKnockout")',
>
>                         data: { stateCd: selectedStateCd, countyCd:
> selectedCountyCd, municipalityCd: municipalityCd },
>
>                         type: 'GET',
>
>                         success: function (data) {
>
>                         if(data) {
>
>                             residencyViewModel.schoolDistricts(data);
>
> *                            // This is where I am attempting to set my
> MVC3 view model i.e., replace the JS var fields with the MVC view model
> fields*
>
>                             var tempCd = data[0].SchoolDistrictCd; //This
> works...
>
>                             var tempDescr = data[0].SchoolDistrictDescr; //This
> works...
>
>                             @("Residency.SchoolDistrictCd") = tempCd;  //This
> does not work....
>
>                             }
>
>                         }
>
>                     });
>
>                 }
>
>             } .bind(this));
>
>         };
>
>         var residencyViewModel = new residencyItems();
>
>         ko.applyBindings(residencyViewModel);
>
>         //Load the states
>
>         $.ajax({
>
>             url: '...@Url.Action( "GetResidencyStates", "MVCKnockout" )',

Paul Tyng

unread,
Jan 1, 2012, 5:21:38 PM1/1/12
to KnockoutJS
I wrote a little .NET library to handle mapping a ViewModel to a
Knockout ViewModel by using the model metadata provider:

https://github.com/paultyng/FluentJson.NET

It allows you to do something like:

@Knockout.ToViewModel(new { name1 = "value1", name2 = 2 })

And get:

{"name1":ko.observable("value1"),"name2":ko.observable(2)}

Of course this doesn't handle all of the round tripping. But if you
use the toJSON method you can send the JSON back to the server and the
built in model binding will take care of it.

To enhance the viewModel on the client side you can do something like:

var viewModel = @Knockout.ToViewModel....

viewModel.someOtherProperty = ko.dependentObservable....

etc.

Not sure if this is exactly what you are looking for, but thought it
may help.

Paul
> ...
>
> read more »

Steves SpamStore

unread,
Jan 1, 2012, 8:43:59 PM1/1/12
to KnockoutJS
It's really the form submission that has me scratching my head.
Without considering Knockout the strongly typed view model passed to
the view via razor. The view model is converted to markup by the Razor
engine and the user fills in values and submits the form/view model
back to the controller. The view model on the client must be bound
again (maybe by Razor?) when it is included in the receiving
controller action. It seems like the resultant view model markup
should be able to be set by code just like the user populates them and
then delivered back to the controlled with the default binding
mechanism.

What you are stating makes sense based upon what I am seeing in
debugger, I just have to get my head wrapped around it. I have seen
posts regarding how to convert the Razor view model to a JS view model
send that back to the controller via a JSON bind. I guess I should
just try it to see what a happens to my client (unobtrusive
JavaScript) validation.

Thanks very much for your response; it definitely helps me develop my
understanding of how things work.

Steve
> ...
>
> read more »

Steves SpamStore

unread,
Jan 1, 2012, 9:05:38 PM1/1/12
to KnockoutJS
Paul,
I will take a look at this. This might be a really stupid question
but how does this differ than doing a statement like the following:

var initialModelData = @Html.Raw( new
System.Web.Script.Serialization.JavaScriptSerializer().Serialize(Model));

I guess this would convert the model that Razor provides to a
JavaScript view model without the bindings...

Like I said I will have to look into this a little more. Thank you
for your posting; I appreciate it.

Steve
> ...
>
> read more »

Mark

unread,
Jan 2, 2012, 12:49:07 AM1/2/12
to KnockoutJS
Use your Razor syntax like this:

@Html.EditorFor(model => model.Country, new {data_bind="value:
country"})

Notice that you have to do data_bind instead of data-bind. The syntax
for using dashes when you define attributes using a Razor command is
that you must represent dashes with underscores. The rendered markup
converts these underscores to dashes.

Steve mentioned that the Razor is processed on the server. Before the
markup is sent to the web page visitor it has all of the code executed
and substitutions are made in those places that you put those Razor
code nuggets. If you set an Output cache attribute decorator on your
controller action then this processed markup is stored to cache and
the markup is sent to the visior. The next visitor receives this page
from cache and the Razor code nuggets are not processed again.

The javascript code that you then place in your scripts tags executes
when the visitor loads the page in their browser and the textbox for
Country will bind to the Country oberservable in your knockout
viewmodel.

If you made a form using the MVC helper methods for making a form then
all of your validation will work if you add just a little bit more to
your code.

A lot of us MVC guys are using jquery unobtrusive validation.
Microsoft just makes it work for us out of the box and we really don't
need to learn how things work. When it comes to integrating this
technology with knockout then we are ignorant and think it must be
knockout's fault for not doing this for us.

Fortunately, with a little critical thinking you will find the
solution is very easy.

What you want to happen is you want to have your normal MVC generated
form, then you want to click a submit button, then the form does not
submit as normal, then a function of your knockout viewmodel is
called, then you check if the validation was valid or not, and then
you use json and ajax to send data to the server, and then you bind
that json data back to your mvc view model on the server side and
process the results.

Here is one way you can make that happen:

Tweak your MVC BeginForm method to generate a form that uses
FormMethod.Get, goes to no action, and give the fom an id such as add-
form
After ko.applyBindings $('form#add-
form').data("validator").settings.submitHandler = viewModel.save
In the viewModel.save method check if($('form#add-form').valid())
{ then do your knockout insert stuff and submit data to server using
json and ajax. }
In your controller action that receives the json data serialize the
data back into a class and process it.

Mark
> *Can a JavaScript variable from a knockout call be mapped or assigned to a
> MVC3 view model variable, i.e., MVC3 view model variable = javascript
> knockout value?  Can Knockout be implemented with MVC3 view models?*
>
> The Sample code below is from a project I pulled together to isolate this
> problem in my application.  Note that in the code section starting with "
> this.muncipalityCd.subscribe(function (municipalityCd) {" is where I am
> trying to set the MVC3 view model variable.   Also, at the end of the
> sample there is another possible approach that I have listed.
>
> Thank you for any guidance you can give while approaching this scenario.
>
> *Sample*
>                         url: '...@Url.Action( "GetCounties", "MVCKnockout")',
>
>                         data: { stateCd: stateCd },
>
>                         type: 'GET',
>
>                         success: function (data) {
>
>                             residencyViewModel.counties(data);
>
>                         }
>
>                     });
>
>                 }
>
>             } .bind(this));
>
>             // Whenever the county changes, reset the municipality selection
>
>             this.countyCd.subscribe(function (countyCd) {
>
>                 selectedCountyCd = countyCd;
>
>                 initialData.CountyCd = countyCd;
>
>                 this.muncipalityCd(undefined);
>
>                 this.municipalities(undefined);
>
>                 if (countyCd != null) {
>
>                     $.ajax({
>
>                         url: '...@Url.Action( "GetMunicipalities",
> "MVCKnockout")',
>
>                         data: { stateCd: selectedStateCd, countyCd:
> countyCd },
>
>                         type: 'GET',
>
>                         success: function (data) {
>
>                             residencyViewModel.municipalities(data);
>
>                         }
>
>                     });
>
>                 }
>
>             } .bind(this));
>
>             // Whenever the municipality changes, reset the school district
> selection
>
>             this.muncipalityCd.subscribe(function (municipalityCd) {
>
>                 selectedMunicipalityCd = municipalityCd;
>
>                 initialData.MunicipalityCd = municipalityCd;
>
>                 this.schoolDistictCd(undefined);
>
>                 this.schoolDistricts(undefined);
>
>                 if (municipalityCd != null) {
>
>                     $.ajax({
>
>                         url: '...@Url.Action( "GetSchoolDistricts",
> "MVCKnockout")',
>
>                         data: { stateCd: selectedStateCd, countyCd:
> selectedCountyCd, municipalityCd: municipalityCd },
>
>                         type: 'GET',
>
>                         success: function (data) {
>
>                         if(data) {
>
>                             residencyViewModel.schoolDistricts(data);
>
> *                            // This is where I am attempting to set my
> MVC3 view model i.e., replace the JS var fields with the MVC view model
> fields*
>
>                             var tempCd = data[0].SchoolDistrictCd; //This
> works...
>
>                             var tempDescr = data[0].SchoolDistrictDescr; //This
> works...
>
>                             @("Residency.SchoolDistrictCd") = tempCd;  //This
> does not work....
>
>                             }
>
>                         }
>
>                     });
>
>                 }
>
>             } .bind(this));
>
>         };
>
>         var residencyViewModel = new residencyItems();
>
>         ko.applyBindings(residencyViewModel);
>
>         //Load the states
>
>         $.ajax({
>
>             url: '...@Url.Action( "GetResidencyStates", "MVCKnockout" )',
> ...
>
> read more »

Weej

unread,
Jan 2, 2012, 9:01:08 AM1/2/12
to KnockoutJS
Hi Steve, here's another tweak for your understanding of the process:
Razor is only going act on the @##### in the view before it's sent to
the client. It's not going to get involved again on the return
submission. Razor's domaine is just to render a view into HTML and
ship it out.

The word "Binding" causes the mists to rise around me :-) but here's
what I've discovered:

The form submission is really interesting. MVC (at least and maybe
ASP.NET) has a cool method to convert user-entered data in a form Form
submission into the objects that your server code understands. You
may know this already but this is also doable with simple Json data
submissions from client side Ajax calls. All you have to do is add a
line in your Global.asax:

protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
ValueProviderFactories.Factories.Add(new
JsonValueProviderFactory()); <---- add this line
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}

This line handles all the conversions from Json to your objects. One
thing to be sure to do however is that each of your DTO classes has to
have a PARAMETERLESS CONSTRUCTOR! (I cant tell you how much trouble
that caused me.) It can have more than one constructor but must have
a parameterless constructor so that the JsonValueProviderFactory can
instantiate an object to fill with the Json data that comes in. It
then tries to matchup the Json field labels with the members in your
class.

In a Form submission I trap the submit action and send it to ko via a
method in my client side viewModel something like this:

updatePayer: function () {
var payerJson = ko.toJSON({ payerDTO:
viewModel.selectedPayer });
$.ajax("/provider/PayerUpdateAjax", {
data: payerJson,
type: "post",
contentType: "application/json",
success: function (result) {
etc...
}

Then the controller reconstitutes the payerDto automagically:

public JsonResult PayerUpdateAjax(PayerDTO payerDto)
{
var origId = payerDto.PayerCode;
var errList = new ErrorList();
if (!payerDto.IsValid(out errList))
return Json(new { result = "error", errorList = errList });
var payer = payerDto.ToPayer();
{
try
{
if (_payerRepos.GetPayerByCode(origId) == null)
_payerRepos.Add(payer);
else
_payerRepos.UpdatePayerRecord(payer);
_payerRepos.Update();
}
catch (Exception e)
{
errList.Add("Form", e.Message);
}
}
if (errList.Count > 0)
return Json(new { result = "error", errorList = errList },
JsonRequestBehavior.AllowGet);
return Json(new { result = "success", listDto = payerDto,
passedId = origId });
}


Anyway, that's how binding happens in the controller. Just have a
receiving method in your controller that has your object as a
parameter.

(BTW, I totally missed the obvious in my original response: rather
than using jQuery or JavaScript to poke a value into your form's
field, best to use ko's data-bind="value: tempCd"

I hope this makes sense...
> ...
>
> read more »- Hide quoted text -
>
> - Show quoted text -

Mark

unread,
Jan 2, 2012, 9:52:41 AM1/2/12
to KnockoutJS
Thanks for the tip about the JsonValueProviderFactory. I am looking
forward to trying that out.

+1 geek point to you sir.

SHOguy

unread,
Jan 3, 2012, 1:38:23 PM1/3/12
to KnockoutJS
I wrote a bunch of classes and helper methods to let me bind with
knockout and still end up with a form that posts back to the server
side view model.

This let's me write code like this:

@using (Html.BeginForm())
{
<table>
<tbody>
@using (var person in Html.KnockoutForEach(m => m.People))
{
<tr>
<td>@person.KnockoutTextBoxFor(p => p.FirstName)</
td>
<td>@person.KnockoutTextBoxFor(p => p.LastName)</
td>
<td><button data-bind="click: Remove">Remove</
button></td>
</tr>
}
</tbody>
</table>
<button data-bind="click: AddPerson">Add Person</button>
<button type="submit">Save People</button>
}

<script type="text/javascript">
@Html.KnockoutViewModelFor()

PeopleViewModel.prototype.AddPerson = function() {
viewModel.People.push(new Person());
};

Person.prototype.Remove = function() {
viewModel.People.remove(this);
}

var viewModel = new PeopleViewModel(@Html.ToJson(Model));

ko.applyBindings(viewModel);
</script>

The really cool thing is that I was able to include all the niceties
of client-side validation from data annotations and everything.

I've considered starting a project on Codeplex for it, if people are
interested.

loganl...@gmail.com

unread,
Sep 13, 2012, 10:23:19 AM9/13/12
to knock...@googlegroups.com, sho...@gmail.com
I know that this post is a bit old, but I'd be very interested in seeing or collaborating on that code. I'm running into a similar issue between cleaning binding MVC3 viewmodels to knockout viewmodels and back again during posts.

If there's already a codeplex project for it, let me know where it is. I'll continue looking for it in the mean time. 

jo...@mouch.name

unread,
Jan 23, 2013, 9:47:11 PM1/23/13
to knock...@googlegroups.com, sho...@gmail.com
I'd be interested in using this code if you have it available.
Reply all
Reply to author
Forward
0 new messages