This is related to my another question here ! I am trying to create a custom validation extender without using validation library.
Am not able to extend my extender on to multiple observable. In the below scenario the extender is applied on the Password field but not on the Retype Password field.
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
<script type="text/javascript" src="knockout-3.4.0.js"></script>
Name:<input type="text" data-bind="value:Name" /><br />
Already A User: <input type="checkbox" data-bind="checked:AlreadyUser" /><br />
Password:<input type="password" data-bind="value:Password,visible:PasswordVisible" /><br />
Retype Password:<input type="password" data-bind="value:RetypePassword,visible:PasswordVisible" /><br />
<input type="button" value="Submit" onclick="validateModel();" />
<script type="text/javascript" >
var pageModel;
ko.extenders.Validate = function (target, validateOptions) {
target.HasErrors = ko.computed(function () {
var newValue = target();
var required = validateOptions.required();
var validationType = validateOptions.validationType;
if (ko.unwrap(required)) {
switch (validationType) {
case "Text":
return newValue == '';
default:
target.HasErrors(false);
break;
}
}
return false;
}, null, { deferEvaluation: true }).extend({ notify: 'always' });
return target;
};
//The model itself
var ViewModel = function () {
var self = this;
self.Name = ko.observable('');
self.AlreadyUser = ko.observable(false);
//computed variable that sets the visibility of the password field. I have to clear the password when am making it invisible
self.PasswordVisible = ko.computed(function () { return !this.AlreadyUser(); }, this).extend({ notify: 'always' });
//this field is only required when visible
self.Password = ko.observable('').extend({ Validate: { required: function () { return self.PasswordVisible(); }, validationType: "Text" } });
self.RetypePassword = ko.observable('').extend({ Validate: { required: function () { return self.PasswordVisible(); }, validationType: "Text" } });
self.AlreadyUser.subscribe(function (newVal) { self.RetypePassword(''); });
self.HasErrors = ko.computed(function () { return self.Password.HasErrors() && self.RetypePassword.HasErrors(); }, self);
};
//The method calls on click of button
function validateModel() {
alert(pageModel.HasErrors());
}
//create new instance of model and bind to the page
window.onload = function () {
pageModel = new ViewModel();
ko.applyBindings(pageModel);
};
</script>
</body>
</html>
I copied your code to an interactive snippet and noticed there was a console error... Also, not all paths in your computed
returned a value.
I've fixed these issues and everything works as you'd expect. Did you check the console before posting?
Errors:
newValue
was not definedComputed mistake:
target()
inside the computed's methodcomputedObs(newVal)
inside the method.var pageModel;
ko.extenders.Validate = function(target, validateOptions) {
target.HasErrors = ko.computed(function() {
var required = validateOptions.required();
var validationType = validateOptions.validationType;
var newValue = target();
if (ko.unwrap(required)) {
switch (validationType) {
case "Text":
return newValue == '';
default:
return false
}
}
return false;
}, null, {
deferEvaluation: true
}).extend({
notify: 'always'
});
return target;
};
//The model itself
var ViewModel = function() {
var self = this;
self.Name = ko.observable('');
self.AlreadyUser = ko.observable(false);
//computed variable that sets the visibility of the password field. I have to clear the password when am making it invisible
self.PasswordVisible = ko.computed(function() {
return !this.AlreadyUser();
}, this).extend({
notify: 'always'
});
//this field is only required when visible
self.Password = ko.observable('').extend({
Validate: {
required: function() {
return self.PasswordVisible();
},
validationType: "Text"
}
});
self.RetypePassword = ko.observable('').extend({
Validate: {
required: function() {
return self.PasswordVisible();
},
validationType: "Text"
}
});
self.AlreadyUser.subscribe(function(newVal) {
self.RetypePassword('');
});
self.HasErrors = ko.computed(function() {
return self.Password.HasErrors() && self.RetypePassword.HasErrors();
}, self);
};
//The method calls on click of button
function validateModel() {
alert(pageModel.HasErrors());
}
//create new instance of model and bind to the page
window.onload = function() {
pageModel = new ViewModel();
ko.applyBindings(pageModel);
};
.has-error {
background:red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
Name:
<input type="text" data-bind="value:Name" />
<br />Already A User:
<input type="checkbox" data-bind="checked:AlreadyUser" />
<br />Password:
<input type="password" data-bind="value:Password, visible:PasswordVisible, css: {'has-error': Password.HasErrors }" />
<br />Retype Password:
<input type="password" data-bind="value:RetypePassword,visible:PasswordVisible, css: {'has-error': RetypePassword.HasErrors }" />
<br />
<input type="button" value="Submit" onclick="validateModel();" />