Ed Staub
Ed Staub

Reputation: 15690

How should a Formly validation function contribute to error messages?

I have an asynchronous Formly field-validation function that is used in several forms and checks multiple aspects of the field. I'd like to be able to "return" (in a general sense) error text from the field-validation function that spells out exactly what is wrong with the field.

What is the best way to do that? I'd guess that I want to emit the text into the scope, but I'm not sure where. I've dug through all the examples (I think) and don't see anything germane.

Upvotes: 4

Views: 3261

Answers (2)

Dustin Hodges
Dustin Hodges

Reputation: 4195

I do this through a combination of formlyValidationMessages and a fieldWrapper. The initial configuration is pretty daunting, but results in a pretty flexible validation system that allows you to handle synchronous and asynchronous validation errors the same. Most of this post was cobbled together from the official async Validation example.

formlyValidationMessages allows you to configure some default error messages for typical validation errors. Here's an example I use in my projects

angular.module('myModule', ['formly']).run(formlyValidationMessages){
    formlyValidationMessages.messages.required = 'to.label + " is required"'
    formlyValidationMessages.messages.max = '"The max value allowed is " + to.max'
    formlyValidationMessages.messages.min = '"The min value allowed is " + to.min'        
}

These are Formly Expressions so they can be strings or functions.

This basically sets a watch on the fields error property in the angular form. If it there's an error in the form for the field, (e.g. form.field.$error.required === true), it'll add max to validation.messages in your field configuration object.

If you need a specific error for a specific field you can add it to the field definition. e.g.

var field = {
    key: 'serialNumber',
    type: 'input'
    ....
    validation: {
      messages: {
        unique: function() {
          return 'Serial number 123 is not unique'
        }
      }
    }
    asyncValidators: {
      unique: {
          expression: function(modelValue, viewValue, scope) {
            return $timeout(
              function(){
                if(modelValue === '123') {
                  throw 'unique failure: 123'  //throw to reject promise
                }
              },
              1000
            )
          }
      }
    }
}

To display this to the user, create a hasError wrapper for your fields that uses ngMessages to create a per field error list for your fields.

module.config(function(formlyConfigProvider) {
  formlyConfigProvider.setWrapper({
    name: 'hasError',
    template: '<div class="form-group" ng-class="{\'has-error\': showError}">' +
      '  <label class="control-label" for="{{id}}">{{to.label}}</label>' +
      '  <formly-transclude></formly-transclude>' +
      '  <div ng-messages="fc.$error" ng-if="showError" class="text-danger">' +
      '    <div ng-message="{{ ::name }}" ng-repeat="(name, message) in ::options.validation.messages" class="message">{{ message(fc.$viewValue)}}</div>' +
      '  </div>' +
      '</div>'
  })
})

Here is a plunker that has a functioning example using bootstrap styling. If you input 123, you'll get an asynchronous validation error, but if you leave it blank you'll get a synchronous one.

Upvotes: 4

Evers
Evers

Reputation: 1908

Angular supports the use of custom validation, so for example, you want to check the username for uniqueness, you can create your own directive to do this.

Like this example: https://docs.angularjs.org/guide/forms

You create your directive with the check for uniqueness and check if the directive is triggered and use ng-show to only show it when its needed.

<span ng-show="form.name.$error.username">This username is already taken!</span>

Upvotes: 0

Related Questions