Ember computed property based validations
In 2.x, we introduced the notion of Options as Functions
which allowed any validator's option to be a function that would be lazily called right before a validation happened. In 3.x, we noticed that such implementation very much resembled the workings of a Computed Property (without the caching of course). Converting our functional approach to an Ember CP approach made defining validations a whole lot simpler.
Before (2.x)
validator('length', {
dependentKeys: ['isEnabled', 'meta.username.minLength', 'meta.username.maxLength'],
disabled(model) {
return !model.get('isEnabled');
},
min(model) {
return model.get('meta.username.minLength')
},
max(model) {
return model.get('meta.username.maxLength')
},
description(model, attribute) {
return model.generateDescription(attribute);
}
});
After (3.x)
validator('length', {
disabled: Ember.computed.not('model.meta.username.isEnabled'),
min: Ember.computed.readOnly('model.meta.username.minLength'),
max: Ember.computed.readOnly('model.meta.username.maxLength'),
description: Ember.computed(function() {
// CPs have access to the `model` and `attribute`
return this.get('model').generateDescription(this.get('attribute'));
}).volatile() // Disable caching and force recompute on every get call
});
Some more reasons why this is better:
dependentKeys
collection.and
, computed.or
, computed.filterBy
, etc.)There might be instances where your validator is dependent on external properties. For this reason, we introduced dependentKeys
in 2.x. In 3.x, the only change to this is that all dependent keys must be prefixed with model
.
Before (2.x)
validator('presence', {
presence: true,
dependentKeys: ['someService.someProperty', 'foo', 'bar.baz']
});
After (3.x)
validator('presence', {
presence: true,
dependentKeys: ['model.someService.someProperty', 'model.foo', 'model.bar.baz']
});
Any validator can be declared as a warning validator by setting isWarning
to true. These validators will act as assertions that when return a message, will be placed under warnings
and warningMessages
collections. What this means, is that these validators will not have any affect on the valid state of the attribute allowing you to display warning messages even when the attribute is valid.
password: {
description: 'Password',
validators: [
validator('length', {
min: 4,
max: 10
}),
validator('length', {
isWarning: true,
min: 6,
message: 'What kind of weak password is that?'
})
]
}
By default, all validators are set to be lazily executed, meaning they will only be run if required. To turn this off, just set the lazy
option on your validator to false
model
instead of _model
when declaring custom dependentsbaseDir
to allow for proper cachingallowNonTld
for email format validator @indr
Thank you to all who took the time to contribute!