simplabs/ember-classy-computed

Name: ember-classy-computed

Owner: simplabs

Description: An Ember addon for Class based Computed Properties

Created: 2016-12-13 16:24:25.0

Updated: 2018-03-20 11:48:28.0

Pushed: 2018-05-17 09:59:26.0

Homepage:

Size: 133

Language: JavaScript

GitHub Committers

UserMost Recent Commit# Commits

Other Committers

UserEmailMost Recent Commit# Commits

README

ember-classy-computed

npm version Build Status

ember-classy-computed introduce a mechanism for class based computed properties which essentially enables keeping state in computed properties (as opposed to normal computed properties which are stateless).

Keeping that state inside of the computed property instead of in the instance of the class it is defined on enables new kinds of computed property macros that are currently hard to implement:

Class based computed properties are essentially equivalent to class based helpers.

Use Case

An example use case for a class based computed property is a macro that creates a computed property with dynamic dependent keys that cannot be know upfront.

Defining a computed property that filters a collection property by the value of an attribute of each element is as easy as

eredUsers: Ember.computed('users.@each.isActive', function() {
turn this.get('users').filterBy('isActive')

This will filter the users collection by the isActive attribute of each user so that filteredUsers only includes users for which that attribute is true. This computed property depends on each user's isActive property obviously.

What if the property that the users are to be filtered by might change though? In that case you might write sth. like this:

eredUsers: Ember.computed('users', 'filter', function() {
turn this.get('users').filterBy(this.get('filter'))

This now filter the users by whatever property name is returned by filter. The problem with this is that the filteredUsers property does not depend on any of the individual user's properties anymore so that it would not be recomputed when any of these user's properties change. There is also no way to express the fact that filteredUsers depends on users.@each.isActive when filter is 'isActive' and on users.@each.isAdmin when filter is 'isAdmin'.

Typically this case would be solved by defining an observer on the context object's filter property and whenever that changes redefining the filteredUsers computed property with the correct dependent keys for the current value of filter (an alternative solution would be to override the filter property's set method and redefine filteredUsers there).

That would make it impossible to reuse the implementation though (except in a mixin which leads to other problems though). ember-classy-computed' mechanism for class based computed properties makes it possible to reuse that implementation- by providing a context for the computed property itself that the observer etc. can be defined on. This allows something like:

rt filterByProperty from 'app/computeds/filter-by';



eredUsers: filterByProperty('users', 'filter')

The logic for the filterByProperty macro is encapsulated in the DynamicFilterByComputed class:

pp/computeds/filter-by.js
rt Ember from 'ember';
rt ClassBasedComputedProperty from 'ember-classy-computed';

t { observer, computed: { filter }, defineProperty } = Ember;

t DynamicFilterByComputed = ClassBasedComputedProperty.extend({
ntentDidChange: observer('content', function() {
// This method is provided by the ClassBasedComputedProperty
// base class and invalidates the computed property so that
// it will get recomputed on the next access.
this.invalidate();
,

lterPropertyDidChange: observer('filterProperty', function() {
let filterProperty = this.get('filterProperty');
let property = filter(`collection.@each.${filterProperty}`, (item) => item.get(filterProperty));
defineProperty(this, 'content', property);
,

 This method is called whenever the computed property on the context object
 is recomputed. The same lazy recomputation behavior as for regular computed
 properties applies here of course. The method receives the current values
 of its dependent properties as its arguments.
mpute(collection, filterProperty) {
this.set('collection', collection);
this.set('filterProperty', filterProperty);

return this.get('content');



rt default ClassBasedComputedProperty.property(DynamicFilterByComputed);

Here the computed property's logic is completely self-contained in the DynamicFilterByComputed class so that it can easily be used via the filterByProperty macro while still ensuring correct dependent keys even when the dynamic filter property changes.

Performance

You might wonder whether this adds a huge performance overhead over regular computed properties. While this certainly introduces some overhead, our benchmarks show that for typical use cases, this overhead over functionally equivalent solutions is pretty much negligible.

Installation

ember install ember-classy-computed

License

ember-classy-computed is developed by and © simplabs GmbH and contributors. It is released under the MIT License.


This work is supported by the National Institutes of Health's National Center for Advancing Translational Sciences, Grant Number U24TR002306. This work is solely the responsibility of the creators and does not necessarily represent the official views of the National Institutes of Health.