npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

ember-clothier

v1.0.0

Published

Clothier adds an object-orientated logic of presentation and state management for your data to your Ember application.

Downloads

3

Readme

Ember Clothier

Build Status Docker: wercker status Windows: Build status Ember Observer Score Code Climate

Clothier adds an object-orientated logic for presentation and state management of 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.

Why?

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:

Object Oriented Helpers

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}}

Holding Contextual State

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 { decoratorFactory } from 'ember-clothier/decorate-mixin';

export default Ember.View.extend({
  model: decoratorFactory('activatable'),

  activeItems: Ember.computed('[email protected]', 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}}

Installation

Install via npm:

npm install --save-dev ember-clothier

Compatibility

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 | 0.2.0 | | Ember 1.12.x | 1.0.0 | | Ember 1.13.x | 1.0.0 | | Ember 2.x.x | comming |

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 | comming |

Writing decorators

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');
  }
});

Decorators support

Decorators behave like default Ember.ObjectProxy but they also support proxing to methods of orginal Object. What this means? Basicaly you can call model instance methods on decorator instance and they will be propely delegate to original model. If you define method with some name on decorator this proxy will be overwritten so both methods will be available on decorator instance. decorator.method() calls method defined on decorator where decorator.get('content').method() call original metod on model instance. Other feature which decorators has out of the box is proxy to ember-data meta so even decorator instances should be passed into ember-data relations.

Aliases and Naming Conventions

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
  }
});

Multiple decorating

You can also decorate your model by multiple decorators what clear the way for keep decorators simple sensual.

// we have a activable decorator with 'actived' property in addition
// and editable decorator with 'edited' property in addition.

// eg. for relations
decoratedChildren: decorateRelation('children', 'activatable', 'editable');

// eg. in Route with decorator mixin
// export default Ember.Route.extend(DecorateMixin, {
this.controllerFor('bookmarks').set('model', this.decorate(items, 'activable', 'editable');

Decorating relationships

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.

Decorating Objects and Collections

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. 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.

Computed Decorate

DecorateMixin comes with additional helper functions for creating computed property for decorating attributes.

computedDecorate

This function takes two arguments ­ attributeName and decoratorAlias (decorator name) and returns Ember.computed which returns decorated attribute. This property is recomputed every-time original property is changed. See this simple example:

import Ember from 'ember';
import { computedDecorate } from 'ember-clothier/decorate-mixin';

export defualt Ember.Component.extend({
  // this property is bind from parrent component
  content: [],
  searchables: computedDecorate('content', 'searchable')
});

decoratorFactory

This function takes one argumnet decoratorAlias (decorator name) and returns Ember.computed which return decorated attribute. This property is recomputed every-time you call set on this property. It returns previous value when you call get on it. Example code:

import Ember from 'ember';
import { decoratorFactory } from 'ember-clothier/decorate-mixin';

export default Ember.Component.extend({
  content: decoratorFactory('searchable')
});

then you can bind or set any property to content and it will be atomatically decorated with searchable decorator.

Api Documentation

| 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 | | decoratorFactory | | decorate-mixin | decoratorAlias[String] | Ember.computed | | ModelMixin | | model-mixin | | | | | decorate | | decoratorAlias[String] | decoratedModel[Object] | | decorateRelation | | 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/decorate-mixin';

// decoratorFactory
import { decoratorFactory } from 'ember-clothier/decorate-mixin';

// ModelMixin
import DecorateModelMixin from 'ember-clothier/model-mixin';

// decorateRelation
import { decorateRelation } from 'ember-clothier/model-mixin';

Changelog

See CHANGELOG.md

Building from source

You can build this addon from source by cloning repository with git.

Dependencies:

  • PhantomJS 2.0.0

clone source:

$ git clone git://github.com/globalwebindex/ember-clothier.git

install dependencies:

$ npm install

Running

  • ember server
  • Visit your app at http://localhost:4200.

Running Tests

NPM test uses ember-try for testing addon against multiple versions of Ember and Ember Data.

  • npm test
  • ember test
  • ember test --server

Building

  • ember build

About GlobalWebIndex

globalwebindex

Ember Clothier is maintained by GlobalWebIndex Ltd.

See more about us at www.globalwebindex.net.