Security News
Research
Data Theft Repackaged: A Case Study in Malicious Wrapper Packages on npm
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
ember-clothier
Advanced tools
Clothier adds an object-orientated logic of presentation and state management for your data to your Ember application.
Clothier adds an object-orientated logic of presentation and state management for your data to your Ember application.
Clothier is designed for decorating your data models with presentation logic (which otherwise might be tangled up into procedural helpers) and data based contextual state of your app. It also help you organise and test this layer of your app more effectively.
Chose your own data library. Clothier supports everything from Ember Data to plain Ember.Object instances.
There are many cases were you need to keep some additional logic aroud your data models in your ambitious web application. As Ember developers we facing this every day. There are some examples:
Ember come with support for helpers out of the box. The problem of this solution is that these helpers are procedural and it is not easy to organise and using them well. With Clothier you can define Class that wraps your model around so you can define method based helpers around your data. Isn't it cool? See example:
Default implementation using helpers:
// helpers/format-date.js
import Ember from 'ember';
export function formatDate(date) {
return moment(date).format('Do MMMM YYYY');
}
export default Ember.Helper.helper(formatDate);
// models/model-name.js
import DS from 'ember-data';
export default DS.Model.extend({
name: DS.attr('name')
});
// routes/application.js
import Ember from 'ember';
export default Ember.Route.extend({
model(params) {
return this.store.findRecord('modelName', params.modelId);
}
});
{{format-date model.createdOn}}
Implementation using Clothier:
// decorators/date.js
import ModelDecorator from 'ember-clothier/model-decorator';
export default ModelDecorator.extend({
formatedDate: Ember.computed('createdOn', function() {
return moment(this.get(date)).format('Do MMMM YYYY');
})
});
// models/model-name.js
import DS from 'ember-data';
import ModelMixin from 'ember-clothier/model-mixin';
export default DS.Model.extend(ModelMixin, {
name: DS.attr('name')
});
// routes/application.js
import Ember from 'ember';
export default Ember.Route.extend({
model(params) {
return this.store.findRecord('modelName', params.modelId).decorate('date');
}
});
{{model.formatedDate}}
The other case is even more difficult. Say we need to implement some filtering logic in our app. We have some models
and we want to manage which of these models are selected
around our app so we can reflect this state in our components.
Without Clothier, this should be done directly on models by defining some state attribute which holds this state.
But what if you need to handle states for one model in more than one context?
For example we want to have one state of model that holds isActive
in filter context and other one that handles isMarkedForDelete
.
You can end up with pretty big mess of state logic on your models which have nothing to do with model itself at all.
With Clothier this is all easy. Just define Decorator
class for each case and you're done. Here is simple example:
// decorators/activatable.js
import ModelDecorator from 'ember-clothier/model-decorator';
export default ModelDecorator.extend({
isActive: false, // default value is false
toggleActive() {
this.toggleProperty('isActive');
}
});
// models/model-name.js
import DS from 'ember-data';
import ModelMixin from 'ember-clothier/model-mixin'; // in this case model mixin is not necesary, but it's recommended
export default DS.Model.extend(ModelMixin, {
name: DS.attr('name')
});
// routes/application.js
import Ember from 'ember';
export default Ember.Route.extend({
model() {
return this.store.findRecord('modelName');
}
})
// view/application.js
import Ember from 'ember';
import DecorateMixin { computedDecorate } from 'ember-clothier/decorate-mixin';
export default Ember.View.extend(DecorateMixin, {
activatables: computedDecorate('model', 'activatable'),
activeItems: Ember.computed('activatables.@each.isActive', function() {
return this.get('activatables').filterProperty('isActive', true);
}),
actions: {
clickOnItem(item) {
item.toggleActive();
}
}
});
{{#each model as |item|}}
<div {{action 'clickOnItem' item}} class={{if item.isActive 'active' 'inactive'}}>
{{item.name}}
</div>
{{/each}}
Active items:<br>
{{#each activeItems as |activeItem|}}
{{activeItem.name}}<br>
{{/each}}
Install via npm:
npm install --save-dev ember-clothier
This plugin is compatible with various version of Ember and Ember Data.
Ember Version | compatibility |
---|---|
Ember 1.10.x and older | no |
Ember 1.11.x | OK |
Ember 1.12.x | OK |
Ember 1.13.x | OK |
Ember 2.x.x | no |
Ember 2 compatibility coming soon!
Ember Data version | compatibility |
---|---|
Ember Data 1.0.0-beta18 and older | unknown |
Ember Data 1.0.0-beta19.x | OK |
Ember Data 1.13.x | OK |
Ember Data 2.x.x | unknown |
Put your decorators in app/decorators
directory.
Here is example of basic decorator:
import ModelDecorator from 'ember-clothier/model-decorator';
export default ModelDecorator.extend({
// decorate model with full name attribute
fullName: Ember.computed('firstName', 'lastName', function() {
return this.get('firstName') + this.get('lastName');
}),
// handle state in menu
isActiveInMenu: false,
changeInMenu() {
this.toggleProperty('isActiveInMenu');
}
});
If you do not specify decorator name when decorating object default decorator will be used.
With Ember Data this is done by using modelName key provided in DS.Model
instance.
If you are not using Ember Data you have to specify _modelName
attribute in your model.
The _modelName
attribute should be also use for overwriting default name with Ember Data.
project structure:
app/
|- decorators
| |- user.js
| |- menu-item.js
|- models
| |- user.js
|- routes
|- application.js
// models/user.js
import Ember from 'ember';
import DecoratorMixin from 'ember-clothier/model-mixin';
export default Ember.Object.extend(DecoratorMixin, {
_modelName: 'user', // this.decorate() will lookup for user decorator
name: ''
});
Then in your route:
import Ember from 'ember';
import UserModel from '../models/user';
export default Ember.Route.extend({
model() {
return UserModel.create({ name: 'Tom Dale' });
},
setupController(controller, model) {
this._super(controller, model);
controller.set('user', model.decorate()); // RETURNS MODEL DECORATED WITH USER DECORATOR
controller.set('menuItem', model.decorate('menu-item')); // RETURNS MODEL DECORATED WITH MENU-ITEM DECORATOR
}
});
With Clothier it is simple to decorate both objects and collections.
There are two basic mixins which implements methods for creating decorators instances.
ModelMixin
implements decorate()
method for decorating model instances and helper for decorating its relationships (see below).
DecorateMixin
implements decorate()
method for decorating both objects and collections and helper for creating computed property for both (see below).
The difference is that Decorate methods takes two arguments where first one is model or collection and second one is alias (name) of decorator.
See Api Documentation for more informations.
ModelMixin
comes with additional helper function for decorating model relationships.
This helper takes two arguments relationKey and decoratorAlias(name of decorator) and return Ember.computed
which returns decorated relationship.
See this simple example:
import DS from 'ember-data';
import ModelMixin, { decorateRelation } from 'ember-clothier/model-mixin';
export default DS.Model.extend({
name: DS.attr('string'),
author: DS.belongsTo('user'),
categories: DS.hasMany('categories'),
// decorated relationships
searchableAuthor: decorateRelation('author', 'searchable'),
searchableCategories: decorateRelation('categories', 'searchable')
});
Helpers for decoration relationships works also without ember data.
The only thing which is expected is that first argument is name of model attribute which holds default model/collection in relationship.
You can easily use this the with plain Ember.Object
models or any other Model implementation.
DecorateMixin
comes with additional helper function for creating computed property for decorating attributes.
This helper takes two arguments attributeName and decoratorAlias (decorator name) and return Ember.computed
which return decorated attribute.
This property is recomputed ecerytime original property is changed.
See this simple example:
import Ember from 'ember';
import DecorateMixin { computedDecorate } from 'ember-clothier/decorate-mixin';
export defualt Ember.Component.extend({
// this property is bind from parrent component
content: [],
searchables: computedDecorate('content', 'searchable')
});
Class/Helper | Method | Import from | Arguments | Return |
---|---|---|---|---|
RouteMixin | decorate-mixin | |||
decorate | subject[Array/Object], decoratorAlias[String] | decoratedModel[Object] | ||
computedDecorate | decorate-mixin | attribute[String], decoratorAlias[String] | Ember.computed | |
ModelMixin | model-mixin | |||
decorate | decoratorAlias[String] | decoratedModel[Object] | ||
decorateBelongsTo | model-mixin | relationKey[String], decoratorAlias[String] | Ember.computed | |
decorateHasMany | model-mixin | relationKey[String], decoratorAlias[String] | Ember.computed |
Examples of imports:
// DecorateMixin
import DecorateMixin from 'ember-clothier/decorate-mixin';
// computedDecorate
import { computedDecorate } from 'ember-clothier/computed-decorate';
// ModelMixin
import DecorateModelMixin from 'ember-clothier/model-mixin';
// decorateBelongsTo
import { decorateBelongsTo } from 'ember-clothier/model-mixin';
// decorateHasMany
import { decorateHasMany } from 'ember-clothier/model-mixin';
See CHANGELOG.md
You can build this addon from source by cloning repository with git.
Dependencies:
clone source:
$ git clone git://github.com/globalwebindex/ember-clothier.git
install dependencies:
$ npm install
ember server
NPM test uses ember-try for testing addon against multiple versions of Ember and Ember Data.
npm test
ember test
ember test --server
ember build
Ember Clothier is maintained by GlobalWebIndex Ltd.
See more about us at www.globalwebindex.net.
FAQs
Clothier adds an object-orientated logic of presentation and state management for your data to your Ember application.
We found that ember-clothier demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Research
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
Research
Security News
Attackers used a malicious npm package typosquatting a popular ESLint plugin to steal sensitive data, execute commands, and exploit developer systems.
Security News
The Ultralytics' PyPI Package was compromised four times in one weekend through GitHub Actions cache poisoning and failure to rotate previously compromised API tokens.