How To Avoid Duplicate Code For Constraint Validation In The Model And View Of A Mvc Web App?
Solution 1:
Unfortunately, many MVC application development frameworks do not provide any support for maintaining the integrity constraints code in the model and use it for data validation both in the view (on input and on form submission) and in the model (before save).
I'll try to provide a sketch of the approach that I've developed to solve this multiple validation problem with the HTML5 forms API, and its setCustomValidity
and checkValidity
methods. Since it requires to execute the same code both in the view and in the model, it only works in a JavaScript MVC web app, where we have the same programming language (JavaScript) in both parts of the app, unlike in other (e.g. PHP od Java) web apps, where the backend model code is not in JavaScript.
Normally we have to validate property constraints only. It's natural, therefore, to write a class-level check function that validates all constraints for each property of a model class. For instance, the following check function makes sure that a value for the ISBN property of a Book
object is a 10-digit string or a 9-digit string followed by "X":
Book.checkIsbn = function (isbn) {
if (typeof(isbn) !== "string" || isbn.trim() === "") {
returnnewRangeConstraintViolation("The ISBN must be a non-empty string!");
} elseif (!/\b\d{9}(\d|X)\b/.test( isbn)) {
returnnewPatternConstraintViolation(
'The ISBN must be a 10-digit string or a 9-digit string followed by "X"!');
} else {
returnnewNoConstraintViolation();
}
};
The check function returns an instance of a ConstraintViolation
class, which has a string-valued message property. In the HTML5 form providing the view (or UI), we add an event listener for input
events to the form input field concerned for handling the validation on user input:
isbnInpEl.addEventListener("input", function () {
isbnInpEl.setCustomValidity( Book.checkIsbn( isbnInpEl.value).message);
});
This event listener invokes the setCustomValidity
method, which has a string parameter. We provide the message created by our property check function as the argument for the invocation of setCustomValidity
. If it's empty, this means the user input is valid. Otherwise, if it contains a non-empty constraint violation message, the HTML5 browser will take care of indicating the constraint violation to the user (e.g. by showing a red border for the input field and displaying the message).
For handling the validation on form submission button click, we check all input fields of the form by invoking the HTML5 checkValidity
method on the form element object:
if (formEl.checkValidity()) {
// save
formEl.reset();
}
Finally, for checking the constraints in the model class before saving any new data, we may invoke the check functions in the property setters, as in
Book.prototype.setIsbn = function (isbn) {
var validationResult = Book.checkIsbn( isbn);
if (validationResult instanceofNoConstraintViolation) {
this.isbn = isbn;
} else {
throw validationResult;
}
};
You can find the full example code in my book Building Front-End Web Apps with Plain JavaScript.
Post a Comment for "How To Avoid Duplicate Code For Constraint Validation In The Model And View Of A Mvc Web App?"