I googled around on how to pass mvc model to knockoutjs and it seems there are two ways:
- Using @Html.Raw(Json.Encode(Model))
- Using $.get or $.ajax
Which of the ways is a best practice of passing mvc model to knockoutjs? I know it is a per requirement basis but it seems using $.get is more cleaner versus the @Html.Raw method.
I use @Html.Raw because there's nothing useful the user can do on the page until the Knockout UI is generated anyway, and any potential trivial time lag due to the extra initial download from writing the JSON into the page is offset by the user not seeing an unnerving delay before the UI is built. I don't have a problem at all with the JSON used to construct my initial view model being directly in my page.
Where I do make efficiency gains is by retrieving any reusable reference data for things like select options (lists of products etc) in a separate dynamic script download from an MVC controller, which then gets cached by the browser. That way they can be reused across view models and the view models only need to store the selected item value.
My approach:
An example:
This means I have an extra AJAX call for the data, but IMO users are coming to realise that data != UI. The benefit is that my UI can be served out quickly because there is no real data access involved. The data load may take some time depending on the database, volume of data, etc, etc. It also gives my code a very clean separation of concerns.
In my mind it is desirable to keep HTML clean and to avoid mixing in inline JavaScript and Data.
I prefer to inject data with an AJAX call to an endpoint.
As you say, it's pretty much a per requirement basis.
If you're doing a "one page application", you're going to do a lot of $.get and $.ajax calls, if you're just rendering a single page, it might be quicker to put the model in the Html, saving an extra request to the server.
Also depends on how much code you want server-side, if my applications need an API anyway, I tend to reusing the API and do $.get and $.ajax calls, if not, I put the model in the Html.
Old question, but I think I have a nice tidy solution for passing model data to a KO view model, in a reusable fashion. Note, I'm using require.js as well.
Add the HtmlHelper extension method, in .NET:
Add the partial view, KnockoutJsBinderPartial (I've had to use aspx):
The model referenced by that view is:
Now, to wire up your .NET model to your knockout view model, all you need to do is:
Note, the Javascript file containing your view model SHOULD NOT call ko.applyBindings and should return the Constructor function for the view model. The constructor should take one argument - your JSON data for the model.
I've successfully used several approaches.
In a strongly typed Razor view, you can write the JavaScript ViewModel object like you would any other HTML, inserting the Model elements as you go. I find this klunky as Razor and JS don't play well together with Visual Studio and Intellisense, but even with a bunch of red squigglies the resulting code works fine.
This code can get ugly in a hurry depending on the complexity of your Model. As you mentioned, you can also serialize the model object into JSON using Html.Raw(). If you go that route, you can use it to build your Knockout ViewModel using the KO Mapping library:
This isn't as kludgy as the first option, but I feel like I'm giving up too much control this way. It means my KO ViewModel is pretty tightly coupled to the structure of my MVC ViewModel, which I may or may not want. Not to mention, for this to work my JavaScript needs to be in my cshtml page which I really don't like. Lastly, both of these approaches are purely server side. For more responsive web pages, like SPIs, you'll want to do more on the client side.
My preference is to use $.getJSON calls client side from the JavaScript itself. At that point, you can process the return data into your ViewModel, either hand rolling or using the mapping library. If you are calling back to actions in your MVC controller, just have the action return a JsonResult type (instead of an ActionResult). (You can also do similar stuff with ContentResult) If you can use the new MVC4 WebAPI, those controllers will return JSON by default.