In Ember, let's say I have an object called FoodStuff
that has a few properties:
export default Ember.Object.extend({
name: null, // REQUIRED: 'Slice of Apple Pie'
calories: null, // OPTIONAL: int: eg. 250
category: null, // REQUIRED: 'Pastry'
rating: null // OPTIONAL: int: 1-5
});
How can I write a 'constructor' in Ember, requiring that the 'name' and 'category' properties be provided at instantiation-time?
Angular seems to approach this with fairly straightforward syntax:
.factory('User', function (Organisation) {
/**
* Constructor, with class name
*/
function User(firstName, lastName, role, organisation) {
// Public properties, assigned to the instance ('this')
this.firstName = firstName;
...
Angular model objects with JavaScript classes
Does Ember have something similar? Currently all my classes are as seen at the top, with a bunch of initially null properties that might or might not be properly set by the caller. At build time (I'm using ember-cli
) I would like for changes in constructor requirements to be caught downstream by the ember build
phase with JSHint.
As far as I know, there is no native way to do this in Ember. But there's nothing impossible! You can tweak Ember a bit to handle the case. Just add an initializer:
/initializers/extend-ember.js:
import Ember from 'ember';
export function initialize() {
Ember.Object.reopen({
/**
* @prop {Array} - array of required properties
*/
requiredAttrs: [],
/**
* Validates existance of required properties
*
* @param {String} attr - attribute name
* @param {*} value - value of the property
* @throws {Error} in case when required property is not set
*/
_validateExistance(attr, value) {
if (this.requiredAttrs.contains(attr) && typeof value === "undefined") {
throw new Error("Attribute " + attr + " can't be empty!");
}
},
/**
* Sets value of a property and validates existance of required properties
*
* @override
*/
set(key, value) {
this._validateExistance(key, value);
return this._super(key, value);
}
});
Ember.Object.reopenClass({
/**
* Creates object instance and validates existance of required properties
*
* @override
*/
create(attrs) {
let obj = this._super(attrs);
if (attrs) {
obj.requiredAttrs.forEach((key) => {
obj._validateExistance(key, attrs[key]);
});
}
return obj;
}
});
}
export default {
name: 'extend-ember',
initialize: initialize
};
Then you can use requiredAttrs
property on any class to define which properties are required. It will throw an exception if you try to create an instance with empty required properties or if you try to set an empty value to required property.
let MyModel = Ember.Object.extend({
prop1: null,
prop2: null,
requiredAttrs: ['prop2']
});
let ChildModel = MyModel.extend({
prop3: null,
requiredAttrs: ['prop2', 'prop3']
});
// throws exception
let obj1 = MyModel.create({
prop1: 'val1'
});
// no exception
let obj2 = MyModel.create({
prop2: 'val2'
});
// throws exception
obj2.set('prop2', undefined);
// throws exception
let obj3 = ChildModel.create({
prop3: 'val3'
});
// no exception
let obj4 = ChildModel.create({
prop2: 'val2',
prop3: 'val3'
});
It will also work on DS.Model
and other Ember entities out of the box, since they all extend Ember.Object
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With