4

I have to design a classic, form based operational web app.

Each form contains some controls, mostly input controls. Many of those controls have validation or behavioral rules, some rules are valid only for a single control (jndependent checks) and some depend on the values of other controls (dependent checks).

Moreover, some controls have the same semantic meaning across different forms.

For example, the "customer name" input field should always have a maximum length of 50 chars and it is shared between many different forms. Another example is that the "documents" combobox is filtered based on the age field (ie: a customer with less than 18 years have different documents). If there are zero documents in that combo, then it should completely disappear.

The rules should be centralized and reused. Even though I can define the rules in functions contained in controllers, I don't want to have the programmer to remember to add a validation rule for a certain field, because I'm sure he won't.

What I am after is an AngularJS-based smart way to define reusable rules for the fields for all the forms, and a way to enforce the programmers to automatically use those rules in the fields. Ideally the rules should be defined on the server and downloaded when needed, because I'll have to redo the check at the server side, for obvious security reasons.

I've looked at angular custom directives, but I'm not sure this is the right way to implement such a thing. It surely works but I'd like to know how to define cross-field rules and enforce their use.

For example, using a custom directive myCustomerName for the customer field name:

app.js var myApp = angular.module("MyApp", []);

myApp.directive("myCustomerName", 
    function() 
    {
        return 
        {
            restrict: 'E',
            templateUrl: 'customer_name.html' 
        };
    }
);

customer_name.html

<div class="form-group">
    <label for="customerName">Customer Name</label>
    <input type="text" class="form-control" id="customerName" ng-model="customerName">
</div>

etc. but then I don't have cross-check rules!

I could instead define a more general custom directive:

myApp.directive("ufeCheck", 
    function() 
    {
        return { 
            restrict: 'E',
            templateUrl: function(e, attr) { 
                return attr.type + '.html';
            }
        };
    }
);

And then use it in the html like:

<ufe_check type="customer_name"></ufe_check>
<ufe_check type="customer_age"></ufe_check>

But, Where would I put the cross field checking? How should I download the server-defined rules?

I think I need a rules engine executor, client side and AngularJS forms-validation compliant.

I've looked at Valdr: https://github.com/netceteragroup/valdr And it's good but the rules are defined only in the client and are not cross field.

vulkanino
  • 9,074
  • 7
  • 44
  • 71
  • Valdr can also load the rules from the server. Please read https://github.com/netceteragroup/valdr#wire-up-your-back-end. – Tome Pejoski Nov 16 '15 at 14:57

2 Answers2

0

it's very common problem and i'm not sure if there is a shelf product that solves all your problems. first of all: you can't just reuse your validation code on backend and frontend because those are two similar but different validations. for example 'repeat password' field is not necessary in the rest api. another example: captcha shouldn't be validated on the frontend.

crossfield validation is easy. you can still encapsulate is in a directive/component that accept field references/names as an input and then uses angular's on-change to verify the logic.

on the server i wouldn't store rules/dsl, i would just reuse js code from the frontend and run that code on the backend (node or other js runtime). if you use your own dsl, there will always be a case that's not supported by your dsl. rules may be very complex so it's easier to have turing complete programming language rather than artificial on-the-fly created dsl.

however i don't know how one can 'enforce' programmer to use it. it will always be easier to simply add new field with 'required' marker rather than searching the code base or the documentation for something similar to what he needs. one way i can think of is to have some tests/code analyser that asserts there is absolutely no custom validation in some folder and that each field has attached one of your custom validators/markers. but i'm not sure it will be convenient for all the other developers

piotrek
  • 13,982
  • 13
  • 79
  • 165
0

You can create a policy on the angle to place calls to the backend in order to validate data . The big advantage of this approach is the centralization of validation in one place . I will not even go into the merits of the advantages of staying in one place rules and validations. You can use a ValidateData class in the backend for example.

There is an api with angle that does this. https://github.com/webadvanced/ng-remote-validate. Usage is very simple, look:

<!-- This defined input for validation with context for this ng-remote-validate-->
<input type="password" 
       name="currentPassword" 
       placeholder="Current password" 
       ng-model="password.current" 
       ng-remote-validate="/customer/validpassword"
       ng-remote-throttle="550"
       ng-remote-method="GET"
       required>

<!-- This defined input for validation with context for this ng-remote-validate-->
<input type="text" 
       name="email" 
       placeholder="Email address" 
       ng-model="email" 
       ng-remote-validate="[ '/customer/email-registered', '/customer/email-restricted' ]"
       ng-remote-throttle="800"
       ng-remote-method="POST"
       required>

<!-- This wait validation -->
<span class="message" ng-show="myForm.inputName.$pending">validating...</span>

<!-- This submit form an run validation -->
<button type="submit" ng-disabled="myForm.$invalid || myForm.$pending" ng-click="...">Go!</button>
Emir Marques
  • 2,603
  • 2
  • 16
  • 22