Skip to content

Instantly share code, notes, and snippets.

@dfreeman
Last active June 9, 2017 13:36
Show Gist options
  • Save dfreeman/623b7a29a0cd899b54a66c3dda56f53a to your computer and use it in GitHub Desktop.
Save dfreeman/623b7a29a0cd899b54a66c3dda56f53a to your computer and use it in GitHub Desktop.
Conditional Changeset Validators
import Ember from 'ember';
import Changeset from 'ember-changeset';
import lookupValidator from 'ember-changeset-validations';
import Validations from 'twiddle/validations/application';
const {
Controller,
computed
} = Ember;
export default Controller.extend({
appName: 'Ember Twiddle',
init() {
this._super();
let changeset = new Changeset({}, lookupValidator(Validations), Validations);
changeset.validate();
this.set('changeset', changeset);
},
error: computed('changeset.error', function() {
return JSON.stringify(this.get('changeset.error'), null, 2);
}),
actions: {
updateContact(value) {
this.set('changeset.contactMethod', value);
this.get('changeset').validate();
}
}
});
<div>
<label>Name {{input type='text' value=changeset.name}}</label>
</div>
<div>
Contact
<select onchange={{action 'updateContact' value='target.value'}}>
<option></option>
<option value="none">None</option>
<option value="email">Email</option>
<option value="phone">Phone</option>
</select>
</div>
<div>
<label>Email {{input type='text' value=changeset.email}}</label>
</div>
<div>
<label>Phone {{input type='text' value=changeset.phone}}</label>
</div>
<pre>{{error}}</pre>
{
"version": "0.10.7",
"EmberENV": {
"FEATURES": {}
},
"options": {
"use_pods": false,
"enable-testing": false
},
"dependencies": {
"jquery": "https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.3/jquery.js",
"ember": "2.9.1",
"ember-data": "2.10.0",
"ember-template-compiler": "2.9.1",
"ember-testing": "2.9.1"
},
"addons": {
"ember-changeset": "*",
"ember-changeset-validations": "*"
}
}
import validateConditional, { equal } from 'twiddle/validators/conditional';
import {
validatePresence,
validateInclusion,
validateFormat
} from 'ember-changeset-validations/validators';
export default {
name: validatePresence(true),
contactMethod: validateInclusion({ list: ['none', 'phone', 'email'] }),
phone: validateConditional({
if: equal('contactMethod', 'phone'),
then: validateFormat({ type: 'phone' }),
else: validatePresence(false)
}),
email: validateConditional({
if: equal('contactMethod', 'email'),
then: validateFormat({ type: 'email' }),
else: validatePresence(false)
})
};
import Ember from 'ember';
const { get, makeArray } = Ember;
export default function validateConditional(options) {
let thenValidators = makeArray(options.then);
let elseValidators = makeArray(options.else);
let max = Math.max(thenValidators.length, elseValidators.length);
// A single validator can't return an array of validations,
// so we return an array of validators instead :/
let validators = [];
for (let i = 0; i < max; i++) {
validators.push(makeValidator(options.if, thenValidators[i], elseValidators[i]));
}
return validators;
}
function makeValidator(condition, thenValidator, elseValidator) {
return (key, newValue, oldValue, changes, content) => {
const conditionPassed = condition(key, newValue, oldValue, changes, content);
const validator = conditionPassed ? thenValidator : elseValidator;
return !validator || validator(key, newValue, oldValue, changes, content);
};
}
export function prop(name, callback) {
return (key, newValue, oldValue, changes, content) => {
let value = changes.hasOwnProperty(name) ? changes[name] : get(content, name);
return callback(value);
};
}
export function equal(name, expected) {
return prop(name, value => value === expected);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment