-
-
Notifications
You must be signed in to change notification settings - Fork 173
/
index.js
311 lines (305 loc) · 8.75 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
import Factory from './validations/factory';
import Validator from './validations/validator';
import { hasValidations as validationDecorator } from './decorators/has-validations';
/**
* ## Installation
* ```shell
* ember install ember-cp-validations
* ```
*
* ## Changelog
* Changelog can be found [here](https://github.com/offirgolan/ember-cp-validations/blob/master/CHANGELOG.md)
*
* ## Live Demo
* A live demo can be found [here](http://offirgolan.github.io/ember-cp-validations/)
*
* ## Looking for help?
* If it is a bug [please open an issue on GitHub](http://github.com/offirgolan/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 Ember from 'ember';
* import DS from 'ember-data';
* 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
*
* export default DS.Model.extend(Validations, {
* 'username': attr('string'),
* 'password': attr('string'),
* 'email': attr('string')
* });
* ```
*
* ## Objects
*
* You can also use the generated `Validations` mixin on any `Ember.Object` or child
* of `Ember.Object`, like `Ember.Component`. For example:
*
* ```javascript
* // components/x-foo.js
*
* import Ember from 'ember';
* import { validator, buildValidations } from 'ember-cp-validations';
*
* const Validations = buildValidations({
* bar: validator('presence', true)
* });
*
* export default Ember.Component.extend(Validations, {
* bar: null
* });
* ```
*
* ```javascript
* // models/user.js
*
* export default Ember.Object.extend(Validations, {
* username: null
* });
* ```
*
* ## A Note on Testing & Object Containers
*
* To lookup validators, container access is required, which can cause an issue with `Ember.Object` creation
* if the object is statically imported. The current fix for this is as follows.
*
* **Ember < 2.3.0**
*
* ```javascript
* // routes/index.js
*
* import User from '../models/user';
*
* export default Ember.Route.extend({
* model() {
* const container = this.get('container');
* return User.create({ username: 'John', container })
* }
* });
* ```
*
* **Ember >= 2.3.0**
*
* ```javascript
* // routes/index.js
*
* import User from '../models/user';
*
* export default Ember.Route.extend({
* model() {
* return User.create(
* Ember.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 Ember from 'ember';
* 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://offirgolan.github.io/ember-cp-validations/docs/modules/Validators.html#message).
*
* ```javascript
* const Validations = buildValidations({
* username: 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
* })
* });
* ```
*
* ### Nested Keys
*
* When declaring object validations (not including Ember Data models), it is possible to validate child objects from the parent object.
*
* ```javascript
* import Ember from 'ember';
* 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 Ember.Component.extend(Validations, {
* acceptTerms: false,
* user: {
* firstName: 'John',
* lastName: 'Doe' ,
* account: {
* number: 123456,
* }
* },
* isFormValid: Ember.computed.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 const hasValidations = validationDecorator;
export default {
buildValidations,
validator,
hasValidations
};