Reputation: 153
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
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
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
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