Search code examples
knockout.jsknockout-validation

advice required on rendering a server model as a ko model with validation


I have a form that needs to be upgraded to use ko and ko validation. The html fields are shown below. I also have a C# MVC model that represents the page, i.e. firstname, lastname and email etc.. I'm seeking advice what the best approach is to handle the view-model and validation correctly.. The other issue I have is that I want the view-model to be separated into different sections to represent the page although the server model is one big model..

Any advice very welcome. Many thanks,

HTML elements

<div id="section1">
    <input data-bind="value: FirstName" />
    <input data-bind="value: Lastname" />
</div>
<div id="section2">
    <input data-bind="value: Email" />
</div>

I've experimented with outputting the C# model onto the page into a JS variable, like this:

View

<script>
  var serverModel = <%=ViewData.Model..%>;
</script>

Rendered result of the above line

<script>
  var serverModel = { FirstName: 'aaa', Lastname: 'bbb', Email: 'a@b.com'};
</script>

And then using ko mapping to create a view-model from the json server model.

JS

viewModel = ko.mapping.fromJS(serverModel);

I would like the view-model to look essentially something like the following but is this a good approach/ possible? Thanks!

viewModel = (function() {
    var section1 = (function() {
        return {
          firstname: ko.observable(),
          lastname: ko.observable()
    });

    var section2 = (function() {
        return {
          email: ko.observable()
    });

});

UPDATE

Possibly something like this

$(function() {

    my.viewModel = function() {
        var section1 = {
            firstname: ko.observable('hello'),
            lastname: ko.observable('there')
        },
        section2 = {
            email: ko.observable('aa@bb.com')
        });
        return {
            section1: section1,
            section2: section2
        };
    }();

    ko.applyBindings(new my.viewModel());

});

UPDATE

think this is it!

http://jsfiddle.net/Cf8Ap/12/


Solution

  • This is what I've come up with which has validation on different sections as displays the errors at the top of the section. This just demonstrates client side validation using the knockout validation plugin. You would also need to have validation on your server side model using validation attributes to ensure the data is always validated.

    html:

    <div data-bind="validationOptions: { insertMessages: false }">
        <div id="section1" data-bind="with: section1">
            <div class="validationElement" data-bind="visible: !isValid()">
                <p data-bind="validationMessage: firstName"></p>
                <p data-bind="validationMessage: lastName"></p>
            </div>
            <input data-bind="value: firstName" />
            <input data-bind="value: lastName" />
        </div>
        <div id="section2" data-bind="with: section2">
            <div class="validationElement" data-bind="visible: !isValid()">
                <p data-bind="validationMessage: email"></p>
            </div>
            <input data-bind="value: email" />
        </div>
    </div>
    

    javascript:

    var viewModel;
    
    $(function () {
        var modelFromServer = {
            firstName: 'John',
            lastName: 'Jones',
            email: 'john.jones@gmail.com'
        };
    
        viewModel = new ViewModel(modelFromServer);
        ko.applyBindings(viewModel); 
    });
    
    var ViewModel = function(model) {
        var self = this;
    
        //using validatedObservable here so I can do isValid on each section
        this.section1 = ko.validatedObservable(new Section1(model));
        this.section2 = ko.validatedObservable(new Section2(model));
    };
    
    var Section1 = function(model) {
        var self = this;
    
        //just have basic required and length validation here
        self.firstName = ko.observable(model.firstName).extend({ 
            required: {message: 'Please enter a first name'},
            maxLength: {params: 20, message: 'Please enter a valid first name'}
            });
    
        //just have basic required and length validation here
        self.lastName = ko.observable(model.lastName).extend({ 
            required: { message: 'Please enter a last name'},
            maxLength: { params: 20, message: 'Please enter a valid last name' }
            });
    };
    
    var Section2 = function(model) {
        var self = this;
    
        //using email validation here
        self.email = ko.observable(model.email).extend({ 
            required: { message: 'Please enter an email address' },
            email: { message: 'Please enter a valid email address' }
            });
    }
    

    http://jsfiddle.net/4DRAh/1/