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: diff --git a/src/components/Select.vue b/src/components/Select.vue index 022e33f..f315dc4 100644 --- a/src/components/Select.vue +++ b/src/components/Select.vue @@ -251,7 +251,35 @@ * @type {Function} * @default {null} */ - onChange: Function + onChange: Function, + + /** + * Enable/disable creating options from searchInput. + * @type {Boolean} + */ + taggable: { + type: Boolean, + default: false + }, + + /** + * User defined function for adding Options + * @type {Function} + */ + createOption: { + type: Function, + default: function (newOption) { + let value = newOption + let firstOption = this.options ? this.options[0] : null + if (firstOption && typeof firstOption === 'object' ) { + value = { + value + } + value[this.label] = newOption + } + return value + } + } }, data() { @@ -267,13 +295,15 @@ this.onChange && val !== old ? this.onChange(val) : null }, options() { - this.$set('value', this.multiple ? [] : null) + if (!this.taggable) { + this.$set('value', this.multiple ? [] : null) + } }, multiple( val ) { this.$set('value', val ? [] : null) }, filteredOptions() { - this.typeAheadPointer = 0; + this.typeAheadPointer = 0 }, }, @@ -352,7 +382,7 @@ return this.value.indexOf(option) !== -1 } - return this.value === option; + return this.value === option }, /** @@ -379,7 +409,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 } @@ -413,6 +443,12 @@ typeAheadSelect() { if( this.filteredOptions[ this.typeAheadPointer ] ) { this.select( this.filteredOptions[ this.typeAheadPointer ] ); + } else if (this.taggable && this.search.length){ + let option = this.createOption(this.search) + this.$set('options', [option, ...this.options]) + this.$nextTick(() => { + this.select(option) + }) } if( this.clearSearchOnSelect ) { diff --git a/test/unit/Select.spec.js b/test/unit/Select.spec.js index 71385e8..7c235b3 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,8 +212,45 @@ describe('Select.vue', () => { }) }) }) -}) + it('can adding option if taggable enabled and search is not empty', () => { + const vm = new Vue({ + template: '