Search code examples
ember.jsember-dataember-cli

How to execute a CP only when the value is changed for the first time?


I'm writing a small validation component that displays an error message if the value is blank/emtpy.

I'm in a bit of a tricky situation.

The parent template:

  {{#validation-wrapper isNew=model.isNew value=model.name presence=true minimum=5}}
    {{input value=model.name}}
  {{/validation-wrapper}}

The component's computed property:

  isPresenceValid: Ember.computed('value', {
    get() {
      return Ember.isPresent(this.get('value'));
    }
  }),

The component template:

{{#if hasErrors}}
  <div class="errors animated bounceIn">
    {{#if presence}}
      <p class="{{if isPresenceValid '-green' '-red'}}"><i class="fa {{if isPresenceValid 'fa-check' 'fa-close'}}"> Must be present</i></p>
    {{/if}}

    {{#if minimum}}
      <p class="{{if isMinimumValid '-green' '-red'}}"><i class="fa  {{if isMinimumValid 'fa-check' 'fa-close'}}"> Must be less than {{minimum}}</i></p>
    {{/if}}
  </div>
{{/if}}

{{yield}}

On page load. value will always be blank. Which means this CP will return false, triggering the template to display an error.

I only want this CP to execute if the value was changed at any point.

Which also means. On page load, if value is blank. Don't display any errors. However, if the user types a value and then removes it. Thats the time the CP executes (returns false).

Any suggestions on how to go about this?


Solution

  • Basically you want the field to be always valid if it is the same as its initial value. So, we just need to save it on init time and compare it to the current value. shouldValidate acts like a toggle to let us know if the value has changed. Example component:

    //app/components/base-validation-component.js
    export default Ember.Component.extend({
    
      didInitAttrs() {
        this.set('initialValue', this.get('value'));
      }
    
      shouldValidate: Ember.computed('value', 'initialValue', function() {
        return this.get('value') !== this.get('initialValue');
      }),
    
      isValid: Ember.computed('shouldValidate', 'value', {
        return this.get('shouldValidate') ? this.validate(this.get('value')) : true;
      }),
    
      validate(value) {
        return Ember.isPresent(value);
      }
    
    })
    

    I also abstracted away the validate(value) method. This way you can subclass this component and just override that method, preserving all of this initial value logic. Example:

    //app/components/positive-validation-component.js
    export default BaseValidationComponent.extend({
      validate(value) {
        return value > 0;
      }
    })