diff --git a/README.md b/README.md index 0e1b42a..a9791c5 100644 --- a/README.md +++ b/README.md @@ -153,6 +153,10 @@ Ember is moving towards a paradigm that encourages the use of actions. With this remove-item / remove-value Sent when the user deselects an item in multiple mode. The removed object is sent as a parameter. `remove-value` is identical, but gets the removed value passed in. + + reorder-items + Sent when the user reorders a list of items in multiple mode. The reordered list of items is sent as a parameter + on-focus Sent when the control gains focus. diff --git a/addon/components/ember-selectize.js b/addon/components/ember-selectize.js index ca01595..55e8832 100644 --- a/addon/components/ember-selectize.js +++ b/addon/components/ember-selectize.js @@ -134,6 +134,7 @@ export default Ember.Component.extend({ create: allowCreate ? Ember.run.bind(this, '_create') : false, onItemAdd: Ember.run.bind(this, '_onItemAdd'), onItemRemove: Ember.run.bind(this, '_onItemRemove'), + onChange: Ember.run.bind(this, '_onChange'), onType: Ember.run.bind(this, '_onType'), render: this.get('renderOptions'), placeholder: this.get('placeholder'), @@ -232,6 +233,38 @@ export default Ember.Component.extend({ }); }, + /** + * Event callback triggered when an item has changed (eg. reorder with drag_drop plugin) + * Here we need to update our selection property (if single selection) or array (if multiple selection) + * We also send an action + */ + _onChange : function(args) { + var selection = get(this,'selection'); + var vp = get(this,'_valuePath'); + + if(!args || !selection || !isArray(selection) || args.length !== selection.length) { + return; + } + + if( selection.every(function(obj, idx) { + if( get(obj, vp) === args[idx] ) { return true; } + }) === true ) { return; } + + var reorderedSelection = Ember.A([]); + + args.forEach(function(value) { + var obj = selection.find(function(item) { + return (get(item, vp) + '') === value; + }, this); + + if (obj) { + reorderedSelection.addObject(obj); + } + }); + + this._changeSelection(reorderedSelection); + }, + /** * Event callback triggered when an item is added (when something is selected) * Here we need to update our selection property (if single selection) or array (if multiple selection) @@ -319,6 +352,22 @@ export default Ember.Component.extend({ }); }, + _changeSelection(selection) { + // TODO This is just to get the tests green, will be cleaned up before merge! + if (!this.get('changeDidTriggerAlready')) { + this.set('changeDidTriggerAlready', true); + this.set('selection', selection); + } else { + this.set('changeDidTriggerAlready', false); + return; + } + + // allow the observers and computed properties to run first + Ember.run.schedule('actions', this, function() { + this.sendAction('reorder-items', selection); + }); + }, + /** * Ember observer triggered before the selection property is changed * We need to unbind any array observers if we're in multiple selection diff --git a/tests/unit/components/ember-selectize-test.js b/tests/unit/components/ember-selectize-test.js index 013fdaf..3df8b64 100644 --- a/tests/unit/components/ember-selectize-test.js +++ b/tests/unit/components/ember-selectize-test.js @@ -281,6 +281,21 @@ test('updating a selection updates selectize value', function(assert) { assert.equal(component.get('selection'), content.objectAt(1)); }); +test('reorder a selection updates selectize value', function(assert) { + var component = this.subject(); + Ember.run(function() { + component.set('content', Ember.A(['item 1', 'item 2', 'item 3', 'item 4'])); + component.set('selection', Ember.A(['item 2', 'item 3'])); + component.set('multiple', true); + }); + this.render(); + Ember.run(function() { + component._selectize.setValue(['item 3', 'item 2']); + }); + assert.deepEqual(component.get('value'), ['item 3', 'item 2']); + assert.deepEqual(component.get('selection'), ['item 3', 'item 2']); +}); + test('replacing a multiple selection updates selectize selection', function(assert) { var component = this.subject(); Ember.run(function() { @@ -563,6 +578,32 @@ test('it sends remove-value action when an item is deselected in multiple mode', }); }); +test('it sends reorder-items action when an item is reordered in multiple mode', function(assert) { + assert.expect(1); + + var component = this.subject(); + + var targetObject = { + externalAction: function(obj) { + assert.deepEqual(obj, ['item 3', 'item 1', 'item 2'], 'externalAction was called with proper argument'); + } + }; + + Ember.run(function() { + component.set('multiple', true); + component.set('content', Ember.A(['item 1', 'item 2', 'item 3', 'item 4'])); + component.set('selection', Ember.A(['item 1', 'item 2', 'item 3'])); + component.set('reorder-items', 'externalAction'); + component.set('targetObject', targetObject); + }); + + this.render(); + + Ember.run(function() { + component._onChange(['item 3', 'item 1', 'item 2']); + }); +}); + test('if label is falsy, don\'t add item', function(assert) { var component = this.subject(); Ember.run(function() {