Mandatory fields validation with knockoutjs extenders

Knockout is a lightweight javascript library that help us to bind the UI with a model and build rich web UI interactions.

The main behaviour of this library are the observable variables, that allow us to make a bidirectional binding between the html fields and the view model of the page.

An interesting feature is extend the observable variables, enriching them with some aditional functionalities; in this example we’ll extend the observable variables with a control for the mandatory fields.

The extender

The extenders allow us to “extend” an observable variable with some behaviours; in this case, we want to add a control for the mandatory fields:


ko.extenders.required = function(target, message) {
target.hasError = ko.observable(false);
target.errorMessage = ko.observable(message || "The field is mandatory.");

function validate(value) {
target.hasError(value ? false : true);
}

validate(target());
target.subscribe(validate);

return target;
};

The function accept two parameters, the target object and the message to show and has the related properties.

The function “validate” set the correct value of hasError property, is called when the main function is loaded and it has been binded to the target object.

We’ll use this extender in our web page.

The view model

We define the view model of the page.


function ViewModel() {
var self = this;

self.FirstName = ko.observable("").extend({ required: "" });
self.LastName = ko.observable("").extend({ required: "" });

self.OnSubmit = ko.observable(false);
self.OnSendData = ko.observable(false);

self.Submit = function () {
self.OnSubmit(true);

if (!self.FirstName.hasError() && !self.LastName.hasError()) {
self.SendData();
}
}

self.Unsubmit = function () {
self.OnSubmit(false);
}

self.SendData = function () {
self.OnSendData(true);
}
}

Has you can see, we are using the extender in the properties definition; we extend the FirstName and LastName properties with the “required” extender; the syntax:

self.FirstName = ko.observable(“”).extend({ required: “” });

means that we pass to the extender two parameters, the first one is the target property (the observable) and the second one is the message (the empty string).

In the submit function we check the value of the hasError property and then we send the data.

The page

Now we are ready to implement the web page.


<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="utf-8" />

		<link rel="stylesheet" type="text/css" href="Content/main.css"/>
<script type="text/javascript" src="scripts/jquery-3.1.1.js"></script>
 <script type="text/javascript" src="scripts/knockout-3.4.0.js"></script>
<script type="text/javascript" src="scripts/extenders.js"></script>
 <script type="text/javascript" src="scripts/viewModel.js"></script>

<script type="text/javascript">
 $(function () {
 var vm = new ViewModel();
 ko.applyBindings(vm);
 });
 </script>
</head>
<body>
<script type="text/html" id="field-error">


<div>
 <input type="text" data-bind="value: field, css: { fieldError: $root.OnSubmit() && field.hasError }" />
 <span data-bind="text: field.errorMessage, visible: $root.OnSubmit() && field.hasError" class="labelError"></span>
</div>


 </script>
<div>
<label>First name</label>
<div data-bind="template: { name: 'field-error', data: { field: FirstName } }"></div>
</div>
<div>
<label>Last name</label>
<div data-bind="template: { name: 'field-error', data: { field: LastName } }"></div>
</div>
<div>
<input type="button" data-bind="click: Submit" value="submit" /></div>
<div>
<label data-bind="visible: OnSendData">Send Data!</label></div>
</body>
</html>

We have defined a template “field-error” that is composed by an input text field and by an error label.

The field has a bind to the value and to the css as well:

<input type=”text” data-bind=”value: field, css: { fieldError: $root.OnSubmit() && field.hasError }” />

The css is conditioned to the OnSubmit event and to the hasError property of the extender.

If all of these properties are true, the fieldError class need to be applied.

The error label is similar:

<span data-bind=”text: field.errorMessage, visible: $root.OnSubmit() && field.hasError” class=”labelError”></span>

The only difference is the text, binded to the errorMessage property of the extender, that we have initialized to an empty string in the view model above.

Then we use the template to define the fields:

Finally, the small css used in this example:


.labelError {
color: #ff0000;
}

.fieldError {
border-color: #ff0000;
}

 

Advertisements
Mandatory fields validation with knockoutjs extenders