1

In Aurelia project, I have created a bootstrap modal that will allow users to enter email addresses. At first when the pop-up is triggered, it applies the validation fine. See below image. This is how it looks like when the pop-up is opened for the first time.

enter image description here

Once you enter the validate email address and click on add btn, I am resetting the value of this.setEmail to "" an empty string. So that way users can type new email address to add. But the validation rule that shows the message Email is required is no longer getting triggered. See below example:

enter image description here

See the Plunker link here. Once the page is loaded. Click on the + icon next to email input. It will open a bootstrap modal.

Below is the code and can be seen at above link as well:

email.ts

import { customElement, useView, bindable, bindingMode, inject, observable } from 'aurelia-framework';
import { ValidationRules, ValidationControllerFactory, Validator } from 'aurelia-validation';

@inject(ValidationControllerFactory)
@customElement('email')
@useView('./email.html')
export class Email {
  @bindable public modalName: string;
  @bindable public modalValue: string;
  @bindable public emailAddress: string;
  public emailAddresses = [];
  @observable public setEmail: string;
  public errorMessage: string;
  emailController = null;

  constructor(factory) {
    this.setEmail = '';
    this.emailController = factory.createForCurrentScope();
    ValidationRules.ensure('setEmail')
        .displayName('Email')
        .required()
        .email()
        .on(this);
  }

  public bind() {
    this.emailController.validate();
  }

  private joinEmails() {
    this.emailAddress = this.emailAddresses.join(";");
  }

  private isUniqueEmail = (email: string) => {
    return (this.emailAddresses.indexOf(email) === -1)
  }

  public addEmail() {
    if (this.setEmail) {
      if(!this.isUniqueEmail(this.setEmail))
      {
        this.errorMessage = "You must provide unique email address.";
        return;
      }
      this.emailAddresses.push(this.setEmail);
      this.joinEmails();
      this.setEmail = '';
    }
    else
    {
      this.errorMessage = "You must provide an email address."
    }
  }

  public setEmailChanged(newValue, oldValue) {
    console.log({oldValue: oldValue, newValue: newValue});
  }

  public removeEmail(index) {
    this.emailAddresses.splice(index, 1);
    this.joinEmails();
    console.log(this);
  }
}

email.html

<template>
  <!-- Modal -->
  <div class="modal fade" id="${modalName}" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
    <div class="modal-dialog" role="document">
      <div class="modal-content">
        <div class="modal-header">
          <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
          <h4 class="modal-title" id="myModalLabel">Add Email Address</h4>
        </div>
        <div class="modal-body">
          <div class="input-group">
            <input type="text" id="setEmail" name="setEmail" class="form-control" value.bind="setEmail & validateOnChangeOrBlur" />
            <span class="input-group-btn">
              <button class="btn btn-primary"
                      disabled.bind="emailController.errors.length > 0" 
                      click.delegate="addEmail()">Add
              </button>
            </span>
          </div>
          <input type="text" value.bind="emailAddress" hidden />
          <span class="text-danger" repeat.for="error of emailController.errors">${error.message}</span>
          <span class="text-danger" if.bind="errorMessage">${errorMessage}</span>
          <div>
            <ul class="list-group" if.bind="emailAddresses.length > 0" style="margin-top: 10px;">
              <li class="list-group-item" repeat.for="e of emailAddresses">
                ${e} <span class="glyphicon glyphicon-remove text-danger pull-right" style="cursor: pointer;" click.delegate="removeEmail($index)"></span>
              </li>
            </ul>
          </div>
        </div>
        <div class="modal-footer">
          <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
        </div>
      </div>
    </div>
  </div>
</template>
Ray
  • 1,095
  • 3
  • 18
  • 43

1 Answers1

1

In your addEmail() function after the line this.setEmail = ''; call the validate again with this.emailController.validate();

The validate() method returns a Promise so you may want to handle any rejections as you would normally see this section of the validation docs Validation Controller specifically the sub section 'validate & reset'.

I'm guessing you expected this to happen automatically because of the 2-way binding and the validateOnChangeOrBlur binding behavior the reason it didn't is that the JavaScript setting the value doesn't trigger DOM events so you need to manually call or fire a synthetic event.

Aquila Sands
  • 1,471
  • 1
  • 20
  • 28
  • Aquila, thank you for your response. I was able to trigger validation by adding `this.emailController.validate();` after `this.setEmail = '';`. You are right. I was hoping that `validateOnChangeOrBlur` would take care of it for me. Thanks for clarifying for me. – Ray Apr 23 '18 at 15:19
  • @Ray Aquila already eluded this but didn't explicitly mention it: `validateOnChange` means it validates on the `change` event of the element, not when the value of the targeted property changes. The docs say this on the trigger: "Validate the binding when it updates the model due to a change in the view." – Fred Kleuver Apr 23 '18 at 15:23
  • Thanks Fred for clarifying. :) – Ray Apr 24 '18 at 11:39