UNPKG

ember-cp-validations

Version:
317 lines (310 loc) 9.01 kB
import Factory from './validations/factory'; import Validator from './validations/validator'; /** * ## Installation * ```shell * ember install ember-cp-validations * ``` * * ## Changelog * Changelog can be found [here](https://github.com/adopted-ember-addons/ember-cp-validations/blob/master/CHANGELOG.md) * * ## Live Demo * A live demo can be found [here](http://adopted-ember-addons.github.io/ember-cp-validations/) * * ## Looking for help? * If it is a bug [please open an issue on GitHub](http://github.com/adopted-ember-addons/ember-cp-validations/issues). * * @module Usage */ /** * ## Models * * The first thing we need to do is build our validation rules. This will then generate a Mixin that you will be able to incorporate into your model or object. * * ```javascript * // models/user.js * * import { validator, buildValidations } from 'ember-cp-validations'; * * const Validations = buildValidations({ * username: validator('presence', true), * password: [ * validator('presence', true), * validator('length', { * min: 4, * max: 8 * }) * ], * email: [ * validator('presence', true), * validator('format', { type: 'email' }) * ], * emailConfirmation: [ * validator('presence', true), * validator('confirmation', { * on: 'email', * message: '{description} do not match', * description: 'Email addresses' * }) * ] * }); * ``` * * Once our rules are created and our Mixin is generated, all we have to do is add it to our model. * * ```javascript * // models/user.js * * import Model from '@ember-data/model'; * * export default Model.extend(Validations, { * 'username': attr('string'), * 'password': attr('string'), * 'email': attr('string') * }); * ``` * * ## Objects * * You can also use the generated `Validations` mixin on any `EmberObject` or child * of `EmberObject`, like `Component`. For example: * * ```javascript * // components/x-foo.js * * import Component from '@ember/component'; * import { validator, buildValidations } from 'ember-cp-validations'; * * const Validations = buildValidations({ * bar: validator('presence', true) * }); * * export default Component.extend(Validations, { * bar: null * }); * ``` * * ```javascript * // models/user.js * * import EmberObject from '@ember/object'; * * export default EmberObject.extend(Validations, { * username: null * }); * ``` * * ## A Note on Testing & Object Containers * * To lookup validators, container access is required, which can cause an issue with `EmberObject` creation * if the object is statically imported. The current fix for this is as follows. * * **Ember < 2.3.0** * * ```javascript * // routes/index.js * * import Route from '@ember/routing/route'; * import User from '../models/user'; * * export default Route.extend({ * model() { * const container = this.get('container'); * return User.create({ username: 'John', container }) * } * }); * ``` * * **Ember >= 2.3.0** * * ```javascript * // routes/index.js * * import { getOwner } from '@ember/application'; * import Route from '@ember/routing/route'; * import User from '../models/user'; * * export default Route.extend({ * model() { * return User.create( * getOwner(this).ownerInjection(), * { username: 'John' } * ); * } * }); * ``` * * This also has ramifications for Ember Data model tests. When using [Ember QUnit's `moduleForModel`](https://github.com/emberjs/ember-qunit#ember-data-tests) * (or [Ember Mocha's `setupModelTest`](https://github.com/emberjs/ember-mocha#setup-model-tests)), you will need to specify all validators * that your model depends on: * * ```javascript * moduleForModel('foo', 'Unit | Model | model', { * needs: ['validator:presence'] * }); * ``` * * @module Usage * @submodule Basic */ /** * ### Default Options * * Default options can be specified over a set of validations for a given attribute. Local properties will always take precedence. * * Instead of doing the following: * * ```javascript * const Validations = buildValidations({ * username: [ * validator('presence', { * presence: true, * description: 'Username' * }), * validator('length', { * min: 1, * description: 'Username' * }), * validator('my-custom-validator', { * description: 'A username' * }) * ] * }); * ``` * * We can declare default options: * * ```javascript * const Validations = buildValidations({ * username: { * description: 'Username' * validators: [ * validator('presence', true), * validator('length', { * min: 1 * }), * validator('my-custom-validator', { * description: 'A username' * }) * ] * }, * }); * ``` * * In the above example, all the validators for username will have a description of `Username` except that of the `my-custom-validator` validator which will be `A username`. * * ### Global Options * * If you have specific options you want to propagate through all your validation rules, you can do so by passing in a global options object. * This is ideal for when you have a dependent key that each validator requires such as the current locale from your i18n implementation, or * you want easily toggle your validations on/off. As of 3.x, all dependent keys must be prefixed with `model`. * * ```javascript * const Validations = buildValidations(validationRules, globalOptions); * ``` * * ```javascript * import { validator, buildValidations } from 'ember-cp-validations'; * * const Validations = buildValidations({ * firstName: { * description: 'First Name' * validators: [ * validator('presence', { * presence: true, * dependentKeys: ['model.foo', 'model.bar'] * }) * ] * }, * lastName: validator('presence', true) * }, { * description: 'This field' * dependentKeys: ['model.i18n.locale'], * disabled: computed.readOnly('model.disableValidations') * }); * ``` * * Just like in the default options, locale validator options will always take precedence over default options and default options will always take precedence * over global options. This allows you to declare global rules while having the ability to override them in lower levels. * * This rule does not apply to `dependentKeys`, instead they all are merged. In the example above, __firstName__'s dependentKeys will be * `['model.i18n.locale', 'model.foo', 'model.bar']` * * ### Computed Options * * All options can also be Computed Properties. These CPs have access to the `model` and `attribute` that is associated with the validator. * * Please note that the `message` option of a validator can also be a function with [the following signature](http://adopted-ember-addons.github.io/ember-cp-validations/docs/modules/Validators.html#message). * * ```javascript * import { computed } from '@ember/object'; * import { not, readOnly } from '@ember/object/computed'; * * const Validations = buildValidations({ * username: validator('length', { * disabled: not('model.meta.username.isEnabled'), * min: readOnly('model.meta.username.minLength'), * max: readOnly('model.meta.username.maxLength'), * description: computed('model', 'attribute', function() { * // CPs have access to the `model` and `attribute` * return this.get('model').generateDescription(this.get('attribute')); * }) * }) * }); * ``` * * ### Nested Keys * * When declaring object validations (not including Ember Data models), it is possible to validate child objects from the parent object. * * ```javascript * import Component from '@ember/component'; * import { alias } from '@ember/object/computed'; * import { validator, buildValidations } from 'ember-cp-validations'; * * const Validations = buildValidations({ * 'acceptTerms': validator('inclusion', { in: [ true ] }), * 'user.firstName': validator('presence', true), * 'user.lastName': validator('presence', true), * 'user.account.number': validator('number') * }); * * export default Component.extend(Validations, { * acceptTerms: false, * user: { * firstName: 'John', * lastName: 'Doe' , * account: { * number: 123456, * } * }, * isFormValid: alias('validations.isValid'), * }); * ``` * * @module Usage * @submodule Advanced */ /** * ### [__Ember-Intl__](https://github.com/ember-intl/cp-validations) * * ```bash * ember install @ember-intl/cp-validations * ``` * * ### [__Ember-I18n__](https://github.com/jasonmit/ember-i18n-cp-validations) * * ```bash * ember install ember-i18n-cp-validations * ``` * * @module Usage * @submodule I18n Solutions */ export const buildValidations = Factory; export const validator = Validator; export default { buildValidations, validator, };