From 22591d1542535f04c01e5b5f82722b50ec64541a Mon Sep 17 00:00:00 2001 From: nanotronic Date: Thu, 24 Mar 2016 15:29:32 +0100 Subject: [PATCH 1/6] Let user add options from search --- src/components/Select.vue | 47 ++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/src/components/Select.vue b/src/components/Select.vue index 0377a8d..bbd0d09 100644 --- a/src/components/Select.vue +++ b/src/components/Select.vue @@ -251,7 +251,34 @@ * @type {Function} * @default {null} */ - onChange: Function + onChange: Function, + + /** + * Enable/disable creating options from searchInput. + * @type {Boolean} + */ + tagable: { + type: Boolean, + default: false + }, + + /** + * User defined function for adding Options + * @type {Function} + */ + createOption: { + type: Function, + default: function (value) { + let firstOption = this.options[0] + if (firstOption && typeof firstOption === 'object' ) { + value = { + value + } + value[this.label] = value + } + return value + } + } }, data() { @@ -267,13 +294,15 @@ this.onChange && val !== old ? this.onChange(val) : null }, options() { - this.$set('value', this.multiple ? [] : null) + if (!this.optionAdded) { + this.$set('value', this.multiple ? [] : null) + } }, multiple( val ) { this.$set('value', val ? [] : null) }, filteredOptions() { - this.typeAheadPointer = 0; + this.typeAheadPointer = 0 }, }, @@ -351,7 +380,7 @@ return this.value.indexOf(option) !== -1 } - return this.value === option; + return this.value === option }, /** @@ -378,7 +407,7 @@ getOptionLabel( option ) { if( typeof option === 'object' ) { if( this.label && option[this.label] ) { - return option[this.label]; + return option[this.label] } else if( option.label ) { return option.label } @@ -412,6 +441,14 @@ typeAheadSelect() { if( this.filteredOptions[ this.typeAheadPointer ] ) { this.select( this.filteredOptions[ this.typeAheadPointer ] ); + } else if (this.tagable && this.search.length){ + let option = this.createOption(this.search) + this.optionAdded = true + this.options.unshift(option) + this.$nextTick(() => { + this.optionAdded = false + this.select(option) + }) } if( this.clearSearchOnSelect ) { From 179bb5c346155878add2c9f16f00f3a080eedf2f Mon Sep 17 00:00:00 2001 From: nanotronic Date: Thu, 24 Mar 2016 16:01:09 +0100 Subject: [PATCH 2/6] use es6 spread --- src/components/Select.vue | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/Select.vue b/src/components/Select.vue index bbd0d09..ad23687 100644 --- a/src/components/Select.vue +++ b/src/components/Select.vue @@ -294,7 +294,7 @@ this.onChange && val !== old ? this.onChange(val) : null }, options() { - if (!this.optionAdded) { + if (!this.isAdding) { this.$set('value', this.multiple ? [] : null) } }, @@ -443,11 +443,11 @@ this.select( this.filteredOptions[ this.typeAheadPointer ] ); } else if (this.tagable && this.search.length){ let option = this.createOption(this.search) - this.optionAdded = true - this.options.unshift(option) + this.isAdding = true + this.$set('options', [option, ...this.options]) this.$nextTick(() => { - this.optionAdded = false this.select(option) + this.isAdding = false }) } From 7127131bfa0ce4fea60a3e7402c9ca71e2aec5aa Mon Sep 17 00:00:00 2001 From: nanotronic Date: Thu, 24 Mar 2016 18:20:13 +0100 Subject: [PATCH 3/6] adding tests --- test/unit/Select.spec.js | 46 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/test/unit/Select.spec.js b/test/unit/Select.spec.js index 71385e8..f2b9ebf 100644 --- a/test/unit/Select.spec.js +++ b/test/unit/Select.spec.js @@ -3,6 +3,14 @@ import Vue from 'vue' import vSelect from '../../src/components/Select.vue' +function trigger (target, event, process) { + var e = document.createEvent('HTMLEvents') + e.initEvent(event, true, true) + if (process) process(e) + target.dispatchEvent(e) + return e +} + describe('Select.vue', () => { it('can accept an array with pre-selected values', () => { @@ -204,6 +212,44 @@ describe('Select.vue', () => { }) }) }) + + it('can adding option if tagable enabled and search is not empty', () => { + const vm = new Vue({ + template: '
', + components: { vSelect }, + data: { + value: ['one'], + options: ['one','two','three'] + } + }).$mount() + vm.$children[0].search = 'four' + + trigger(vm.$children[0].$els.search, 'keyup', function (e) { + e.keyCode = 13 + }) + + expect(vm.$children[0].options[0]).toEqual('four') + }) + + it('should select added option if tagable enabled and search is not empty', (done) => { + const vm = new Vue({ + template: '
', + components: { vSelect }, + data: { + value: ['one'], + options: ['one','two','three'] + } + }).$mount() + vm.$children[0].search = 'four' + + trigger(vm.$children[0].$els.search, 'keyup', function (e) { + e.keyCode = 13 + }) + Vue.nextTick(() => { + expect(vm.$children[0].$get('value')).toEqual(['one', 'four']) + done() + }) + }) }) From 7b62ad0a5620abf27fc95319af7dce1e40902bda Mon Sep 17 00:00:00 2001 From: nanotronic Date: Thu, 24 Mar 2016 18:23:50 +0100 Subject: [PATCH 4/6] update readme --- README.md | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index afcd90d..931799d 100644 --- a/README.md +++ b/README.md @@ -121,7 +121,34 @@ export default { * an action, rather than using :value.sync to retreive the selected value. * @type {[type]} */ - onChange: Function + onChange: Function, + + /** + * Enable/disable creating options from searchInput. + * @type {Boolean} + */ + tagable: { + type: Boolean, + default: false + }, + + /** + * User defined function for adding Options + * @type {Function} + */ + createOption: { + type: Function, + default: function (value) { + let firstOption = this.options[0] + if (firstOption && typeof firstOption === 'object' ) { + value = { + value + } + value[this.label] = value + } + return value + } + } ``` ## Todos: From fd3bf874ad24ea30add92aa7b2c1aae4198938f6 Mon Sep 17 00:00:00 2001 From: nanotronic Date: Mon, 11 Apr 2016 18:47:51 +0200 Subject: [PATCH 5/6] fix typo --- src/components/Select.vue | 4 ++-- test/unit/Select.spec.js | 9 ++++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/components/Select.vue b/src/components/Select.vue index 1b2573c..e7bf99b 100644 --- a/src/components/Select.vue +++ b/src/components/Select.vue @@ -257,7 +257,7 @@ * Enable/disable creating options from searchInput. * @type {Boolean} */ - tagable: { + taggable: { type: Boolean, default: false }, @@ -442,7 +442,7 @@ typeAheadSelect() { if( this.filteredOptions[ this.typeAheadPointer ] ) { this.select( this.filteredOptions[ this.typeAheadPointer ] ); - } else if (this.tagable && this.search.length){ + } else if (this.taggable && this.search.length){ let option = this.createOption(this.search) this.isAdding = true this.$set('options', [option, ...this.options]) diff --git a/test/unit/Select.spec.js b/test/unit/Select.spec.js index f2b9ebf..7c235b3 100644 --- a/test/unit/Select.spec.js +++ b/test/unit/Select.spec.js @@ -213,9 +213,9 @@ describe('Select.vue', () => { }) }) - it('can adding option if tagable enabled and search is not empty', () => { + it('can adding option if taggable enabled and search is not empty', () => { const vm = new Vue({ - template: '
', + template: '
', components: { vSelect }, data: { value: ['one'], @@ -231,9 +231,9 @@ describe('Select.vue', () => { expect(vm.$children[0].options[0]).toEqual('four') }) - it('should select added option if tagable enabled and search is not empty', (done) => { + it('should select added option if taggable enabled and search is not empty', (done) => { const vm = new Vue({ - template: '
', + template: '
', components: { vSelect }, data: { value: ['one'], @@ -252,6 +252,5 @@ describe('Select.vue', () => { }) }) - // also see example testing a component with mocks at // https://github.com/vuejs/vueify-example/blob/master/test/unit/a.spec.js#L22-L43 From f7b24d47e0a620211391d621098340c4b5c40a13 Mon Sep 17 00:00:00 2001 From: nanotronic Date: Wed, 13 Apr 2016 20:23:13 +0200 Subject: [PATCH 6/6] fix call stack exceeded --- src/components/Select.vue | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/components/Select.vue b/src/components/Select.vue index e7bf99b..f315dc4 100644 --- a/src/components/Select.vue +++ b/src/components/Select.vue @@ -268,13 +268,14 @@ */ createOption: { type: Function, - default: function (value) { - let firstOption = this.options[0] + default: function (newOption) { + let value = newOption + let firstOption = this.options ? this.options[0] : null if (firstOption && typeof firstOption === 'object' ) { value = { value } - value[this.label] = value + value[this.label] = newOption } return value } @@ -294,7 +295,7 @@ this.onChange && val !== old ? this.onChange(val) : null }, options() { - if (!this.isAdding) { + if (!this.taggable) { this.$set('value', this.multiple ? [] : null) } }, @@ -444,11 +445,9 @@ this.select( this.filteredOptions[ this.typeAheadPointer ] ); } else if (this.taggable && this.search.length){ let option = this.createOption(this.search) - this.isAdding = true this.$set('options', [option, ...this.options]) this.$nextTick(() => { this.select(option) - this.isAdding = false }) }