Search code examples
aurelia

Aurelia Validation rule (bound to model) does not fire on subsequent activations of a view model


I am trying to expand on the Aurelia Contact Manager Tutorial. Specifically: adding email validation to the contact-details.html view. I have followed the examples in the Validation: Basics documentation and on first pass it worked as expected: Launch application, select a contact from the contact-list module, then update the email to something invalid by removing the '@', then tab away. The validation rule fires and the error message is displayed.

However, if after launching the application I select a first contact followed by a second, hence triggering a second activation of the contact-details module, then the validation rule does not fire.

I have tried a validationController.reset() on activate of the contact-detail and while this will remove any 'old' error messages, the on blur validation will still not fire.

I have tried the two different methods of creating the validation controller (using NewInstance.of(ValidationController) vs ValidationControllerFactory) but both yield the same result.

If, after navigating to a second contact and 'breaking' the validation, I then refresh the browser and reload the page then the validation works again. Until I choose another contact from the list which will then break it again.

I am new to Aurelia and JavaScript frameworks in general and I'm not sure if this is a bug or there is something extra required to handle re-routing to the same page.


Solution

  • That's a good question. There are a couple of things that may be catching you out. I've created a Gist which includes the necessary file modifications to get this working:

    https://gist.github.com/freshcutdevelopment/170c2386f243e7095e276811dab52299

    Gotchas

    Because the view-model you're using for validation is not the backing view-model for the contact-detail.html view file you'll need a separate class which you'll apply the validation rules to. Although it sounds like you've already nailed this part, I'll include it for completeness. You can create this class like so:

    export class Contact {
      email= '';
    }
    

    You can then apply the validation rules to this class as follows:

      ValidationRules
      .ensure(a => a.email).required().email()
      .on(Contact);
    

    The last possible missing puzzle piece here is that you'll need to hook into the screen activation life-cycle hook deactivate() and reset the validation context. This will force the BootstrapValidationRenderer to remove the validation styles from your view.

      deactivate(){
        this.controller.reset();
      }
    

    Validation Workflow

    The steps are as follows:

    1. Inject the controller
    2. Add the validation renderer to the controller
    3. Create the validation model (only needed if the model you want to validate is not the view-model that backs your view)
    4. Apply the validation rules to the model
    5. Determine when to re-set and execute the validation (in this case on the deactivate life-cycle hook.
    6. Apply the validation binding behavior to the view