ember-cp-validations
ember-cp-validations copied to clipboard
Feature Request: hasValidated as validation state
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.
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.
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.
Hmmmmm I see your point. So this leads to two questions:
- When is this flag turned on
- When/how is this flag turned off
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.
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:
I'll see what I can do sometime this week on this.
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 thedidValidate
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 calledvalidate
.
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.
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 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;
},
},
});