Large Scale MVC Web Application - Using Knockout and Razor

I am working on a large scale web application and I am having problems with its correct architecture using knockout and MVC.

I currently have a base view model that I am passing to all of my views containing base data about the currently logged in user

//Example Code
public class BaseViewModel {
    public String FullName;
    public String Email;

    //A bunch of other similar values
}

      

Then I have view models specific to each page of the site (i.e. profile) that inherit the BaseViewModel class

//profile.cshtml
public class UserProfileViewModel : BaseViewModel {
    public String Address;
    public String PhoneNumber;

    //Other similar values
}

//entity.cshtml
public class UserEntityViewModel : BaseViewModel {
    public String EntityValue;
    public Int32 EntityNumber;

    //Other similar values
}

      

I have overridden my entire data model in javascript using observable knockouts so that I can create objects of any type I have in my MVC model. Then I have several view modes defined in javascript, which are basically the same as my MVC view models, allowing for loading, creating, editing, deleting functionality.

I find this works great in cases where I would like to create a new object on the profile page, for example. I can create a new viewmodel instance and bind it to the new jquery dialog when the OK button is clicked. I can trigger an event on my knockout model that will save or create the object.

This architecture doesn't work that well when I want to load data into a specific page (i.e., I would like to populate a profile page using my knockout data model). I run into problems when I need to determine which page I am on and bind a specific view model to that page. I really don't think the following code is very nifty.

$(function() {
    if ($('.tweak-list').length) {
        var id = $('.tweak-list').attr('data-songid');
        var vm = new my.tweaksviewmodel({ songid: id });
        ko.applyBindings(vm);
    }
});

      

Does anyone have any advice on how I should go about doing this? I think it would be better to create the BaseViewModel in javascript and use the knockout display plugin http://knockoutjs.com/documentation/plugins-mapping.html to create my various data models automatically. However, it doesn't really solve the problem of determining which page the model was bound on so that it can load the appropriate data.

Edit 1

There is also a limitation in this architecture that I cannot use when using modal popups to add data, as I need to re-bind the viewmodel to each modal.

Does anyone have any idea?

+3


source to share


1 answer


I suggest you architect it like this:

Create another JavaScript module with a specific KnockOut ViewModel function for each page:

var app = app || {};
app.pages = app.pages || {};

app.pages.userProfile = (function () {

    function UserProfileViewModel() {
        //view model specific code
    };

    function init() {
        ko.applyBindings(new UserProfileViewModel());
    };

    return {
        init: init
    };
}());

      

Indicate which JS module should be used in razor mode:



@model dynamic

@{
    ViewBag.CurrentPageJsHandler = "app.pages.userProfile";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<p>Page specific content</p>

      

Add the page-specific module initialization code to the layout file:

<html>
<body>   
    <div id="content">
        @RenderBody()
    </div>      
    @if (@ViewBag.CurrentPageJsHandler != null)
    {
        <script>
            $(function() {
                app.currentPage = @ViewBag.CurrentPageJsHandler;
                app.currentPage.init();
            });
        </script>
    }    
</body>
</html>

      

This way you can encapsulate all the code associated with the page in different modules. Since each JS module has a unique name, you can chain everything together and include in your layout.

+4


source







All Articles