Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inline Validator #569

Merged
merged 4 commits into from
Feb 16, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 1 addition & 10 deletions addon/validations/factory.js
Original file line number Diff line number Diff line change
Expand Up @@ -751,7 +751,6 @@ function createValidatorsFor(attribute, model) {
let validatorCache = get(validations, '_validators');
let owner = getOwner(model);
let validators = [];
let validator;

// We must have an owner to be able to lookup our validators
if (isNone(owner)) {
Expand All @@ -763,15 +762,7 @@ function createValidatorsFor(attribute, model) {
validationRules.forEach(v => {
v.attribute = attribute;
v.model = model;

// If validate function exists, that means validator was created with a function so use the base class
if (v._type === 'function') {
validator = BaseValidator.create(owner.ownerInjection(), v);
} else {
validator = lookupValidator(owner, v._type).create(v);
}

validators.push(validator);
validators.push(lookupValidator(owner, v._type).create(v));
});

// Add validators to model instance cache
Expand Down
14 changes: 11 additions & 3 deletions addon/validations/validator.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { isNone } from '@ember/utils';
import { deprecate } from '@ember/application/deprecations';

/**
* @module Validators
Expand Down Expand Up @@ -210,13 +211,20 @@ export default function(arg1, options) {
};

if (typeof arg1 === 'function') {
props.validate = arg1;
props._type = 'function';
deprecate(
'[ember-cp-validations] `validator` no longer directly accepts ' +
'a function. Please use the inline validator syntax:' +
"\n\nvalidator('inline', { validate() {} )\n\n",
false,
{ id: 'ember-cp-validations.inline-validator', until: '4.2.0' }
);
props.options.validate = arg1;
props._type = 'inline';
} else if (typeof arg1 === 'string') {
props._type = arg1;
} else {
throw new TypeError(
'[ember-cp-validations] Unexpected type for first validator argument. It should either be a string or a function'
'[ember-cp-validations] Unexpected type for first validator argumentIt must be a string.'
);
}

Expand Down
21 changes: 2 additions & 19 deletions addon/validators/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ const Base = EmberObject.extend({
/**
* Build options hook. Merges default options into options object.
* This method gets called on init and is the ideal place to normalize your options.
* The [presence validator](https://github.com/offirgolan/ember-cp-validations/blob/master/app/validators/presence.js) is a good example to checkout
* The [presence validator](https://github.com/offirgolan/ember-cp-validations/blob/master/addon/validators/presence.js) is a good example to checkout
* @method buildOptions
* @param {Object} options
* @param {Object} defaultOptions
Expand Down Expand Up @@ -302,7 +302,7 @@ const Base = EmberObject.extend({

Base.reopenClass({
/**
* Generate the needed depenent keys for this validator
* Generate the needed dependent keys for this validator
*
* @method getDependentsFor
* @static
Expand Down Expand Up @@ -466,20 +466,3 @@ export default Base;
* @module Validators
* @extends Base
*/

/**
* A validator can also be declared with an inline function. The function will be then wrapped in the {{#crossLink 'Base'}}Base Validator{{/crossLink}} class and used just like any other pre-defined validator.
*
* ```javascript
* // Example
* validator(function(value, options, model, attribute) {
* return value === options.username ? true : `{description} must be ${options.username}`;
* } , {
* username: 'John' // Any options can be passed here
* })
* ```
*
* @class Inline
* @module Validators
* @extends Base
*/
49 changes: 49 additions & 0 deletions addon/validators/inline.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import Base from 'ember-cp-validations/validators/base';
import { assign } from '@ember/polyfills';
import { assert } from '@ember/debug';

/**
* Accepts a custom `validate` function.
*
* ## Examples
*
* ```javascript
* validator('inline', {
* username: 'offirgolan',
* validate(value, options, model, attribute) {
* return value === options.username ?
* true :
* `Username must be ${options.username}`;
* }
* });
* ```
*
* @class Inline
* @module Validators
* @extends Base
*/
export default Base.extend({
/**
* Override the validator's `validate` method with the one that was
* passed in via the options.
*
* @method buildOptions
* @param {Object} options
* @param {Object} defaultOptions
* @param {Object} globalOptions
* @return {Object}
*/
buildOptions(options = {}, ...args) {
assert(
`[validator:inline] You must pass in a validate function`,
options && typeof options.validate === 'function'
);

const opts = assign({}, options);

this.validate = opts.validate;
delete opts.validate;

return this._super(opts, ...args);
}
});
1 change: 1 addition & 0 deletions app/validators/inline.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from 'ember-cp-validations/validators/inline';
6 changes: 4 additions & 2 deletions tests/dummy/app/models/signup.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ import { validator, buildValidations } from 'ember-cp-validations';

let Validations = buildValidations({
name: validator('presence', true),
acceptTerms: validator(value => {
return value || 'You must accept the terms.';
acceptTerms: validator('inline', {
validate(value) {
return value || 'You must accept the terms.';
}
})
});

Expand Down
60 changes: 24 additions & 36 deletions tests/integration/validations/factory-dependent-keys-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,19 +91,17 @@ test('nested ds-error validator creates correct dependent keys', function(assert

test('custom dependent keys - simple', function(assert) {
let Validations = buildValidations({
fullName: validator(
function(value, options, model) {
fullName: validator('inline', {
dependentKeys: ['model.firstName', 'model.lastName'],
validate(value, options, model) {
let firstName = model.get('firstName');
let lastName = model.get('lastName');
if (!firstName || !lastName) {
return 'Full name requires first and last name';
}
return true;
},
{
dependentKeys: ['model.firstName', 'model.lastName']
}
)
})
});

let obj = setupObject(this, EmberObject.extend(Validations));
Expand All @@ -127,19 +125,17 @@ test('custom dependent keys - default options', function(assert) {
fullName: {
dependentKeys: ['model.firstName'],
validators: [
validator(
function(value, options, model) {
validator('inline', {
dependentKeys: ['model.lastName'],
validate(value, options, model) {
let firstName = model.get('firstName');
let lastName = model.get('lastName');
if (!firstName || !lastName) {
return 'Full name requires first and last name';
}
return true;
},
{
dependentKeys: ['model.lastName']
}
)
})
]
}
});
Expand All @@ -166,20 +162,18 @@ test('custom dependent keys - global options', function(assert) {
fullName: {
dependentKeys: ['model.firstName'],
validators: [
validator(
function(value, options, model) {
validator('inline', {
dependentKeys: ['model.lastName'],
validate(value, options, model) {
let firstName = model.get('firstName');
let lastName = model.get('lastName');
let middleName = model.get('middleName');
if (!firstName || !lastName || !middleName) {
return 'Full name requires first, middle, and last name';
}
return true;
},
{
dependentKeys: ['model.lastName']
}
)
})
]
}
},
Expand Down Expand Up @@ -211,19 +205,17 @@ test('custom dependent keys - global options', function(assert) {

test('custom dependent keys - nested object', function(assert) {
let Validations = buildValidations({
page: validator(
function(value, options, model) {
page: validator('inline', {
dependentKeys: ['model.currPage', 'model.meta.pages.last'],
validate(value, options, model) {
let currPage = model.get('currPage');
let lastPage = model.get('meta.pages.last');
if (currPage > lastPage) {
return 'Cannot exceed max page';
}
return true;
},
{
dependentKeys: ['model.currPage', 'model.meta.pages.last']
}
)
})
});

let obj = setupObject(this, EmberObject.extend(Validations), {
Expand Down Expand Up @@ -255,18 +247,16 @@ test('custom dependent keys - nested object', function(assert) {

test('custom dependent keys - array', function(assert) {
let Validations = buildValidations({
friends: validator(
function(value, options, model) {
friends: validator('inline', {
dependentKeys: ['model.friends.[]'],
validate(value, options, model) {
let friends = model.get('friends');
if (!friends || friends.length === 0) {
return 'User must have a friend';
}
return true;
},
{
dependentKeys: ['model.friends.[]']
}
)
})
});

let obj = setupObject(this, EmberObject.extend(Validations), {
Expand Down Expand Up @@ -297,8 +287,9 @@ test('custom dependent keys - array', function(assert) {

test('custom dependent keys - array of objects', function(assert) {
let Validations = buildValidations({
friends: validator(
function(value, options, model) {
friends: validator('inline', {
dependentKeys: ['[email protected]'],
validate(value, options, model) {
let friends = model.get('friends');
if (!friends || friends.length === 0) {
return 'User must have a friend';
Expand All @@ -309,11 +300,8 @@ test('custom dependent keys - array of objects', function(assert) {
}
}
return true;
},
{
dependentKeys: ['[email protected]']
}
)
})
});

let obj = setupObject(this, EmberObject.extend(Validations), {
Expand Down
Loading