1

I have some doubts about AngularJS + Custom Validations, from what I have read and checked by myself:

  • AngularJS provides great helpers for simple field validation (ng-require, ...).
  • The best way to implement a single field custom validation is via directive (not polluting the controller).

My doubts come when we have custom business validations that impact on more than one filed. Let's check the following simple scenario:

simple UI flight status

  • We are editing a flight arrival status, fields: Status (landed / scheduled / delayed), comments (additional info abot the flight status).
  • The business validations that I want to apply is: comments fields is required only if status fields value is "Delayed".

    The way I have implemented it:

Directive + Service

  • Define a directive to take care of Status + Comments field changes (status via $watch).
  • This directive delegates the business validation into a service

    The benefits I think this approach is giving to me are:

  • My business service validation gets isolated.

  • I could easily add unit testing to that business validation.

  • I could reuse it and it doesn't depend on UI elements.

    I have compiled this sample in a JSFiddle (JSFiddle validation sample).

JS:


function MyCtrl($scope) {    
    $scope.arrival = {
        "id": 1,
        "originAirport": "Malaga (AGP)",
        "flightNumber": "Iberia 132",
        "dueAt": "2013-05-26T12:10:10",
        "status": 2,
        "info": "test"
    }
}


myApp.directive('validateinfofield', ['formArrivalValidation', function (formArrivalValidation) {
    return {
        require: "ngModel",
        link: function(scope, elm, attrs, ctrl) {


            ctrl.$parsers.unshift(function(viewValue){
                // Empty? Let's check status
                //if (!viewValue.length && scope.arrival.status == 3) {
                if(formArrivalValidation.validateInfoField(scope.arrival.status, viewValue)) {
                    ctrl.$setValidity('validInfo', true);
                } else {
                    ctrl.$setValidity('validInfo', false);
                }
            });

            // Let's add a watch to arrival.status if the values change we need to 
            // reevaluate, if comments is empty and status is delayes display error
            scope.$watch('arrival.status', function (newValue, oldValue) {
                if (formArrivalValidation.validateInfoField(newValue, scope.editArrivalForm.txInfo.$viewValue)) {
                    ctrl.$setValidity('validInfo', true);
                } else {
                    ctrl.$setValidity('validInfo', false);
                }
            });

        }
    };
}]);

// Validation Service, limited to our "business language"
myApp.factory('formArrivalValidation',

   function () {
       return {
           validateInfoField: function (status, infoField) {
               var isOk = true;

               if (status == 3) {
                   if (infoField == undefined) {
                       isOk = false;
                   } else {
                       if (!infoField.length)
                           isOk = false;
                   }
               }

               return isOk;
           },

       };
   });

Is this a good approach to follow? Is there better and simpler way to achieve this?

Braulio
  • 1,748
  • 14
  • 23
  • [How to add custom validation to an AngularJS form?](https://stackoverflow.com/q/12581439/6521116) – LF00 Nov 14 '17 at 08:21

2 Answers2

2

Regarding this part - "The business validations that I want to apply is: comments fields is required only if status fields value is "Delayed". for comment field set ng-required="flight.status == 'DELAYED'"

avi
  • 178
  • 2
  • 9
  • Hey! pretty smart solution. My concern here is that it's something that falls in the UI layer, we cannot easily add automated unit testing (e.g. some code changes and our unit test battery doesn't detect the change on the UI) on the other hand you get the solution in less than a line of code, quite smart. – Braulio Jun 28 '13 at 15:29
  • To add onto this. You can put the validation in a method on the controller and then unit test the controller.... This should be the accepted answer. – dannypaz Feb 19 '16 at 15:20
0

Coming back to this question... one valid approach could be to write a directive that accepts as parameter a second value (e.g. comments is empty)

Braulio
  • 1,748
  • 14
  • 23