Skip to content

Commit

Permalink
Merge pull request #2 from workmanw/gj/inital
Browse files Browse the repository at this point in the history
add `DidChangeAttrs` mixin
  • Loading branch information
GavinJoyce authored Oct 31, 2017
2 parents 6880a1e + 71d75a9 commit 91ac2a6
Show file tree
Hide file tree
Showing 4 changed files with 609 additions and 19 deletions.
59 changes: 58 additions & 1 deletion addon/index.js
Original file line number Diff line number Diff line change
@@ -1 +1,58 @@
/* Hey @GavinJoyce, add your code here! :) */
import WeakMap from 'ember-weakmap';
import Ember from 'ember';

function isEqual(key, a, b) {
return a === b;
}

export default Ember.Mixin.create({
_didChangeAttrsWeakMap: null, //this tracks previous state of any `trackAttrChanges`
didChangeAttrsConfig: [], //attributes to track

didReceiveAttrs() {
this._super(...arguments);

let weakMap = this.get('_didChangeAttrsWeakMap');

if (weakMap === null) { //first run
let config = this.get('didChangeAttrsConfig');
let trackedAttrs = config.attrs;
let initialValues = {};

for (let i=0; i<trackedAttrs.length; i++) {
let key = trackedAttrs[i];
initialValues[key] = this.get(key);
}

weakMap = new WeakMap();
weakMap.set(this, initialValues);
this.set('_didChangeAttrsWeakMap', weakMap);
}
},

didUpdateAttrs() {
this._super(...arguments);

let config = this.get('didChangeAttrsConfig');
let equalityFn = config.isEqual || isEqual;

let trackedAttrs = config.attrs;
let oldValues = this.get('_didChangeAttrsWeakMap').get(this);
let changes = {};

for (let i=0; i<trackedAttrs.length; i++) {
let key = trackedAttrs[i];
let current = this.get(key);
let previous = oldValues[key];

if (!equalityFn(key, previous, current)) {
changes[key] = { previous, current };
oldValues[key] = current;
}
}

if(Object.keys(changes).length > 0) {
this.didChangeAttrs(changes);
}
},
});
Empty file removed tests/integration/.gitkeep
Empty file.
110 changes: 110 additions & 0 deletions tests/integration/did-change-attrs-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import Ember from 'ember';
import { test, moduleForComponent } from 'ember-qunit';
import hbs from 'htmlbars-inline-precompile';
import DidChangeAttrs from 'ember-did-change-attrs';

function registerComponent(testSuite, hash, klass = Ember.Component) {
testSuite.register('component:x-changer', klass.extend(DidChangeAttrs, hash));
}

moduleForComponent('x-changer', 'Integration | DidChangeAttrs', {
integration: true
});

test('Basic usage', function(assert) {
let changedAttrs, didChangeAttrsCallCount = 0;

registerComponent(this, {
didChangeAttrsConfig: {
attrs: ['email', 'isAdmin']
},

didChangeAttrs(changes) {
this._super(...arguments);

didChangeAttrsCallCount++;
changedAttrs = changes;
}
});

this.set('name', 'Tomster');
this.set('email', '[email protected]');
this.set('isAdmin', false);

this.render(hbs`{{x-changer email=email isAdmin=isAdmin name=name}}`);

assert.equal(didChangeAttrsCallCount, 0, '`didChangeAttrs` is not called on initial render');

this.set('email', '[email protected]');
assert.equal(didChangeAttrsCallCount, 1, '`didChangeAttrs` is called when an attribute changed');

assert.deepEqual(changedAttrs, {
email: {
previous: '[email protected]',
current: '[email protected]'
}
}, '`changedAttrs` contains the attribute changes');

this.set('name', 'TheTomster');
assert.equal(didChangeAttrsCallCount, 1, '`didChangeAttrs` is not called when an untracked attribute is changed');
});

test('Custom isEqual', function(assert) {
let changedAttrs, didChangeAttrsCallCount = 0;

registerComponent(this, {
didChangeAttrsConfig: {
attrs: ['user', 'isAdmin'],
isEqual(key, a, b) {
if (key === 'user') {
return (a && b) ? a.id === b.id : a === b;
}
return a === b;
}
},

didChangeAttrs(changes) {
this._super(...arguments);

didChangeAttrsCallCount++;
changedAttrs = changes;
}
});

this.set('user', { name: 'Tomster', id: '123' });
this.set('isAdmin', false);

this.render(hbs`{{x-changer user=user isAdmin=isAdmin}}`);

assert.equal(didChangeAttrsCallCount, 0, '`didChangeAttrs` is not called on initial render');

this.set('user', { name: 'TheTomster', id: '123' });

assert.equal(didChangeAttrsCallCount, 0, '`didChangeAttrs` is not called because user entities are equal');

this.set('user', { name: 'Zoey', id: '456' });

assert.equal(didChangeAttrsCallCount, 1, '`didChangeAttrs` is called because user entities are not equal');
assert.deepEqual(changedAttrs, {
user: {
previous: {
id: '123',
name: 'Tomster'
},
current: {
id: '456',
name: 'Zoey'
}
}
}, '`user` included in `changedAttrs` because `user.id` is different');

this.set('isAdmin', true);

assert.equal(didChangeAttrsCallCount, 2, '`didChangeAttrs` is called because isAdmin changed');
assert.deepEqual(changedAttrs, {
isAdmin: {
previous: false,
current: true
}
}, '`isAdmin` included in `changedAttrs` because it changed');
});
Loading

0 comments on commit 91ac2a6

Please sign in to comment.