Search code examples
aurelia

Aurelia Validation on dynamically built form


I'm creating a custom element that dynamically generates a user input form. So far it's working quite well, but I'm having problems setting up Aurelia-Validation on it and need some help.

my-form.html

<div class="form-group" repeat.for="control of controls">
  <label>${control.label}</label>
  <div>
    <compose containerless
      view-model="resources/elements/${control.type}/${control.type}" 
      model.bind="{'control': control, 'model': model, 'readonly': readonly}"
      class="form-control"></compose>
  </div>
</div>

I have several different control.type's available and working (my-textbox, my-dropdown, my-datepicker) -- each of them is a custom element. For instance:

Example control (my-textbox.html)

<template>
  <input type="text"
    class="form-control" 
    value.bind="model[control.bind] & validate">
</template>

Parent view:

<my-form controls.bind="controls" model.bind="model" if.bind="controls"></my-form>

Parent view-model:

controls = [
  {label: 'Username', type: 'my-textbox', bind: 'user_username'},
  {label: 'Status', type: 'my-dropdown', bind: 'user_status', enum: 'ActiveInactive', default: '(Choose)'},
  {label: 'Last_login', type: 'my-datepicker', bind: 'user_lastlogin', vc: 'date'}];

ValidationRules
  .ensure('user_username').required().minLength(1).maxLength(10)
  .ensure('user_status').required()
  .ensure('user_lastlogin').required()
  .on(this.model);

I'm getting the error Error: A ValidationController has not been registered. at ValidateBindingBehaviorBase.bind.... However, I only want one validator for the whole dynamically-built form, so I don't want to import validation in each of the controls. What do I do?


Solution

  • It actually works to import the Validation Controller and related resources in the parent form, even though the & validate is attached to the child controls.

    Parent view-model

    import {inject} from 'aurelia-framework';
    import {ValidationControllerFactory, ValidationRules} from 'aurelia-validation';
    import {BootstrapFormRenderer} from 'common/bootstrap-form-renderer';
    
    @inject(Core, ValidationControllerFactory)
    export class MyForm {
      constructor(validationControllerFactory) {
        this.validationCtrl = validationControllerFactory.createForCurrentScope();
        this.validationCtrl.addRenderer(new BootstrapFormRenderer());
      }
      setupValidator() {
        let rules = [];
        this.controls.map(control => {
          if (control.validation) {
            rules.push(ValidationRules.ensure(control.bind).required().rules[0]);
        }
        this.validationCtrl.addObject(this.modelEdit, rules);
      }
    }