ember-cp-validations icon indicating copy to clipboard operation
ember-cp-validations copied to clipboard

Feature Request: hasValidated as validation state

Open jasonmit opened this issue 9 years ago • 9 comments

A common pattern is surfacing validation errors after the user touched a field.

It would be great if this state was stored on the validation object and flipped only when validate or validateSync is invoked and in the case of the async validation - once it's resolved.

Thoughts? I can work on this if there is buy-in.

jasonmit avatar Feb 06 '16 01:02 jasonmit

Im not exactly sold on the idea that this should be part of this library. I feel like we provide enough state properties such as isValidating and isValid (or isTruelyValid), that this type of state should be handled solely by the user.

model.validate().then(() => {
   // do some complex stuff here
  model.set('_hasValidated', true); 
  model.save();
});

I think that the term hasValidated is sort of misleading, in the sense that it implies that calling validate or validateSync actually trigger validations where actually, validations happen automatically via the CPs.

offirgolan avatar Feb 08 '16 21:02 offirgolan

I see everyone having to manage this state https://github.com/offirgolan/ember-cp-validations/blob/bf1e4642d0358fe41f1bee550004831bc4b89a45/tests/dummy/app/controllers/index.js#L33

which I think can be internalized since you know when validate/validateSync was invoked. The advantage of having it internal is to enable flipping the state back, i.e, dirtying any of the attributes that are being validated. Closing and will implement it on my end.

jasonmit avatar Feb 09 '16 01:02 jasonmit

Hmmmmm I see your point. So this leads to two questions:

  1. When is this flag turned on
  2. When/how is this flag turned off

offirgolan avatar Feb 09 '16 04:02 offirgolan

When is this flag turned on

After validate or validateSync are invoked.

When/how is this flag turned off

When an attribute that has a validator is touched.

What I'm saying is just a proposal, so feel free to keep bouncing ideas off me or whoever until you're comfortable with the idea.

jasonmit avatar Feb 09 '16 05:02 jasonmit

Maybe the best way to go about this is (if you have some spare time) to create this feature and open a PR and we can discuss from there :smile_cat:

offirgolan avatar Feb 09 '16 21:02 offirgolan

I'll see what I can do sometime this week on this.

acburdine avatar Apr 26 '16 16:04 acburdine

Hi all! Any updates here? The didValidate property would be very useful for us. Right now to get that functionality, the options are:

  • use targetObject to get the didValidate property (seems brittle) or
  • pass the didValidate property in (seems unnecessary)

In both cases we have to pass didValidate or targetObject down a component chain if there are nested components, which is also :(.

For reference, our use case:

  • Show validation errors when user leaves a field. This we were able to do by waiting to set the field value until focus-out.
  • On submit, show all validation errors (including any fields that have not been focused-out). For this we need didValidate to tell the field that the parent called validate.

Component:

export default Ember.Component.extend({
  classNameBindings: ['hasError:error'],

  didValidate: Ember.computed.oneWay('targetObject.didValidate'),
  hasError: Ember.computed('validation.isInvalid', 'validation.isDirty', 'didValidate', function() {
    return (this.get('validation.isDirty') || this.get('didValidate')) && this.get('validation.isInvalid');
  }),

  validationMessage: Ember.computed('hasError', function() {
    if (this.get('hasError')) {
      return this.get('validation.message');
    }
  }),

  actions: {
    // Don't trigger validations until the field is out of focus
    focusOut: function(value) {
      this.set('value', value);
    }
  }
});

Thanks! Happy to help out also.

v-shan avatar Jun 09 '16 03:06 v-shan

Do we have any progress on this?

I've been trying to find a solution for showing error messages only after field is dirty or model is validated.

Can't seem to find an easy and clean way of doing it.

guitassinari avatar Aug 24 '17 23:08 guitassinari

@guitassinari Figured I would share my solution as I was in the same boat. Basically it just listens for the change event and sets a respective boolean within the component that can be used for whatever purpose.

Template

<form {{action "onChange" on="change"}}>
...
</form>

Component

export default Ember.Component.extend({
  formHasBeenTouched: false,
  formIsValid: computed.and('formHasBeenTouched', 'model.validations.isValid').readOnly(),
  actions: {
    onChange() {
      this.set('formHasBeenTouched', true)
    },
    async onSubmit(e) {
      const account = this.get('account');
      const formIsValid = this.get('formIsValid');

      if (formIsValid) {
        try {
          await this.attrs.submit(account);
        } catch (error) {
          // whoops
        }
      }

      e.preventDefault();
      return false;
    },
  },
});

bbohen avatar Sep 22 '17 02:09 bbohen