Required properties (constructor arguments) in Ember.Object instances

In Ember, let's say I have an object called FoodStuff that has several 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 instance time?

Angular seems to approach this with a fairly simple 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 visible from above, with a bunch of initially zero properties that may or may not be set correctly by the caller. During build (I use ember-cli ), I would like the changes to the constructor requirements to be ember-cli downstream using the ember build phase using JSHint.

+5
source share
2 answers

As far as I know, in Ember there is no own way to do this. But nothing is impossible! You can set up 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 }; 

You can then use the requiredAttrs property for any class to determine which properties are needed. It will throw an exception if you try to create an instance with empty required properties or try to set an empty value to the 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 with DS.Model and other Ember elements out of the box, as they are all extended by Ember.Object .

+2
source

To have runtime checks, you want to override the init method:

 init() { this._super(); Ember.assert('Name cannot be empty', name); // ... } 

So that they can be caught in build , I'm not sure about that. You can use some kind of tool to add static input to Javascript (Typescript and stream come to mind), which may be able to force these properties when creating these objects. You can also write your own tool (such as the ESLint plugin) to test this, but it is probably harder than what it costs. You are probably best off working out a runtime solution and decent test coverage.


Here is an example of your own create() method.

 SomeClass.reopenClass({ create(name, category, calories = null, rating = null) { // Validate your properties Ember.assert('Name cannot be empty', name); // ... // Create the object var obj = this._super({ name, category, calories, rating }); // Do any other setup/validation // Return the object return obj; } }); 
+1
source

Source: https://habr.com/ru/post/1233084/


All Articles