Seth Greenstein
Seth Greenstein

Reputation: 153

Knockout using Mapping and Validation Plugins together. Getting client errors

I'm using knockout js to construct my application with asp.net mvc 4 on the backend. We are using knockout.mapping to populate the observables from MVC Service calls

Now I'm trying to add validation using the Knockout.Validation plugin as follows:

self.sDetail(ko.mapping.fromJS(s));
var validationOptions = { 
                          insertMessages: true, 
                          decorateElement: true,      
                          errorElementClass: 'errorFill' 
                         };
ko.validation.init(validationOptions);
self.sDetail.Year.extend({ required: true });

When I run it I get the following error:

Error: Unable to get property 'extend' of undefined or null reference

When I debug I find that the sDetail appears empty. When I applyBindings the inputs are populated correctly. At what point to I have access to the propertys of the ko viewmodel. Is there a way around this issue?

Upvotes: 1

Views: 4107

Answers (3)

Anders
Anders

Reputation: 17554

For a cleaner and more readable solution use explicit declared VM's

DetailsViewModel = function(data) {
   this.year = ko.observable().extend({ required: true });
   ko.mapping.fromJS(data, {}, this);
};

Used like

new DetailsViewModel(data);

A good practice is to explicit declare all members that do actual domain logic. The presentation only members can be automapped automatic by ko.mapping.

Update: Got downvoted by some douch, but this solution is very valid and readable

http://jsfiddle.net/hww8vk1n/1/

Upvotes: 1

Jeff Mercado
Jeff Mercado

Reputation: 134891

The actual problem in your original code was that you were trying to access the Year property on the observable holding your mapped model, not on the model itself (assuming sDetail is an observable on self which I can only assume is your actual view model). This was what I meant on my comment. You mapped the value the observable holds so you need to read off of that value. You attempted to extend() a property that doesn't exist on observables hence the error.

self.sDetail; // <- your observable holding the model
self.sDetail.Year; // <- undefined, observables don't have a `Year` property
self.sDetail.Year.extend(...); // <- error

The fix there would be to invoke your observable to get the model that it holds and then you can access whatever you want.

self.sDetail().Year.extend({ required: true }); // this should work

That's not to take away from your eventual solution, extending from within the mapping settings would be preferrable as it leads to cleaner code (IMHO).

Upvotes: 1

Seth Greenstein
Seth Greenstein

Reputation: 153

Found a solution here: Knockout Mapping Validation

basically have to extend the properties in the call to mapping

var validationMapping = {
// customize the creation of the name property so that it provides validation
Year: {
    create: function(options) {
        return ko.observable(options.data).extend( {required: true} );
    }
}
};


  self.sDetail(ko.mapping.fromJS(s,validationMapping));
 var validationOptions = { 
                      insertMessages: true, 
                      decorateElement: true,      
                      errorElementClass: 'errorFill' 
                     };
  ko.validation.init(validationOptions);

self.sDetail.Year.extend({ required: true });

Upvotes: 2

Related Questions