From 21ec385718adee2beef8ba1846358926299e4b8e Mon Sep 17 00:00:00 2001 From: Jeff Date: Fri, 12 Jan 2018 22:39:04 -0800 Subject: [PATCH] - add `filter` function prop - rename `filterFunction` to `filterComparator` - add dev example using fuse.js - update jsdocs - update tests --- dev.html | 10 +++-- src/components/Select.vue | 73 ++++++++++++++++++++-------------- src/dev.js | 7 ++-- test/unit/specs/Select.spec.js | 20 +++++++++- 4 files changed, 73 insertions(+), 37 deletions(-) diff --git a/dev.html b/dev.html index 7dbd414..99e4128 100644 --- a/dev.html +++ b/dev.html @@ -40,17 +40,21 @@ - + + + + diff --git a/src/components/Select.vue b/src/components/Select.vue index 911449e..c2a994f 100644 --- a/src/components/Select.vue +++ b/src/components/Select.vue @@ -522,34 +522,6 @@ } }, - /** - * Callback to filter the search result the label text. - * @type {Function} - * @param {Object || String} option - * @param {String} label - * @param {String} search - * @return {Boolean} - */ - filterFunction: { - type: Function, - default(option, label, search) { - return (label || '').toLowerCase().indexOf(search.toLowerCase()) > -1 - } - }, - - filter: { - "type": Function, - default(vm) { - return vm.mutableOptions.filter((option) => { - let label = vm.getOptionLabel(option) - if (typeof label === 'number') { - label = label.toString() - } - return this.filterFunction(option, label, vm.search) - }); - } - }, - /** * An optional callback function that is called each time the selected * value(s) change. When integrating with Vuex, use this callback to trigger @@ -603,6 +575,44 @@ default: true }, + /** + * Callback to determine if the provided option + * should match the current search text. + * @type {Function} + * @param {Object || String} option + * @param {String} label + * @param {String} search + * @return {Boolean} + */ + filterComparator: { + type: Function, + default(option, label, search) { + return (label || '').toLowerCase().indexOf(search.toLowerCase()) > -1 + } + }, + + /** + * Callback to filter results when + * search text is provided. + * @type {Function} + * @param {Array} list of options + * @param {String} search text + * @param {Object} vSelect instance + * @return {Boolean} + */ + filter: { + "type": Function, + default(options, search) { + return options.filter((option) => { + let label = this.getOptionLabel(option) + if (typeof label === 'number') { + label = label.toString() + } + return this.filterComparator(option, label, search) + }); + } + }, + /** * User defined function for adding Options * @type {Function} @@ -995,8 +1005,11 @@ * @return {array} */ filteredOptions() { - let options = this.search.length ? this.filter(this) : this.mutableOptions; - if (this.taggable && !this.optionExists(this.search)) { + if (!this.filterable && !this.taggable) { + return this.mutableOptions.slice() + } + let options = this.search.length ? this.filter(this.mutableOptions, this.search, this) : this.mutableOptions; + if (this.taggable && this.search.length && !this.optionExists(this.search)) { options.unshift(this.search) } return options diff --git a/src/dev.js b/src/dev.js index d4e8c83..385059b 100644 --- a/src/dev.js +++ b/src/dev.js @@ -1,9 +1,9 @@ import Vue from 'vue' import Fuse from 'fuse.js' +import debounce from 'lodash/debounce' import resource from 'vue-resource' import vSelect from './components/Select.vue' import countries from 'docs/data/advanced.js' -import debounce from 'lodash/debounce' import fuseSearchOptions from './fuseSearchOptions' Vue.use(resource) @@ -20,6 +20,7 @@ new Vue({ value: null, options: countries, ajaxRes: [], + people: [], fuseSearchOptions }, methods: { @@ -43,8 +44,8 @@ new Vue({ loading(false) }) }, 250), - fuse({mutableOptions, search}) { - return new Fuse(mutableOptions, { + fuseSearch(options, search) { + return new Fuse(options, { keys: ['title', 'author.firstName', 'author.lastName'], }).search(search); } diff --git a/test/unit/specs/Select.spec.js b/test/unit/specs/Select.spec.js index d6184a8..10d6c95 100644 --- a/test/unit/specs/Select.spec.js +++ b/test/unit/specs/Select.spec.js @@ -322,7 +322,7 @@ describe('Select.vue', () => { expect(JSON.stringify(vm.$refs.select.filteredOptions)).toEqual(JSON.stringify([{label: 'Bar', value: 'bar'}, {label: 'Baz', value: 'baz'}])) }) - it('can use a custom filterFunction passed via props', ()=>{ + it('can determine if a given option should match the current search text', () => { const vm = new Vue({ template: `
`, data: {value: 'foo'}, @@ -333,6 +333,23 @@ describe('Select.vue', () => { vm.$refs.select.search = 'a' expect(JSON.stringify(vm.$refs.select.filteredOptions)).toEqual(JSON.stringify([{label: 'Aoo', value: 'foo'}])) }) + + it('can use a custom filtering method', () => { + const vm = new Vue({ + template: `
`, + data: { + options: ['foo','bar','baz'], + value: 'foo' + }, + methods:{ + customFn(options, search, vm) { + return options.filter(option => option.indexOf(search) > 0) + } + } + }).$mount() + vm.$refs.select.search = 'a' + expect(JSON.stringify(vm.$refs.select.filteredOptions)).toEqual(JSON.stringify(['bar','baz'])) + }) }) describe('Toggling Dropdown', () => { @@ -780,6 +797,7 @@ describe('Select.vue', () => { const vm = new Vue({ template: '
', }).$mount() + vm.$children[0].open = true Vue.nextTick(() => { expect(console.warn).toHaveBeenCalledWith( '[vue-select warn]: Label key "option.label" does not exist in options object {}.' +