Commit 801a9c9d6da5cd275b959dd9c61da376814b0055
Committed by
GitHub
Merge pull request #3739 from SergioCrisostomo/select-patches
Select improvements for edge cases
Showing
2 changed files
with
28 additions
and
16 deletions
Show diff stats
src/components/select/select.vue
... | ... | @@ -82,7 +82,7 @@ |
82 | 82 | import FunctionalOptions from './functional-options.vue'; |
83 | 83 | |
84 | 84 | const prefixCls = 'ivu-select'; |
85 | - const optionRegexp = /^i-option$|^Option$/; | |
85 | + const optionRegexp = /^i-option$|^Option$/i; | |
86 | 86 | const optionGroupRegexp = /option-?group/i; |
87 | 87 | |
88 | 88 | const findChild = (instance, checkFn) => { |
... | ... | @@ -99,7 +99,7 @@ |
99 | 99 | const opts = node.componentOptions; |
100 | 100 | if (opts && opts.tag.match(optionRegexp)) return [node]; |
101 | 101 | if (!node.children && (!opts || !opts.children)) return []; |
102 | - const children = [...(node.children || []), ...(opts && opts.children || [])]; | |
102 | + const children = [...(node.children || []), ...(opts && opts.children || [])]; | |
103 | 103 | const options = children.reduce( |
104 | 104 | (arr, el) => [...arr, ...findOptionsInVNode(el)], [] |
105 | 105 | ).filter(Boolean); |
... | ... | @@ -123,6 +123,18 @@ |
123 | 123 | }; |
124 | 124 | }; |
125 | 125 | |
126 | + const getNestedProperty = (obj, path) => { | |
127 | + const keys = path.split('.'); | |
128 | + return keys.reduce((o, key) => o && o[key] || null, obj); | |
129 | + }; | |
130 | + | |
131 | + const getOptionLabel = option => { | |
132 | + const textContent = (option.componentOptions.children || []).reduce((str, child) => str + (child.text || ''), ''); | |
133 | + const innerHTML = getNestedProperty(option, 'data.domProps.innerHTML'); | |
134 | + return option.componentOptions.propsData.label || textContent || (typeof innerHTML === 'string' ? innerHTML : ''); | |
135 | + }; | |
136 | + | |
137 | + | |
126 | 138 | const ANIMATION_TIMEOUT = 300; |
127 | 139 | |
128 | 140 | export default { |
... | ... | @@ -210,8 +222,11 @@ |
210 | 222 | this.$on('on-select-selected', this.onOptionClick); |
211 | 223 | |
212 | 224 | // set the initial values if there are any |
213 | - if (this.values.length > 0 && !this.remote && this.selectOptions.length > 0){ | |
214 | - this.values = this.values.map(this.getOptionData).filter(Boolean); | |
225 | + if (!this.remote && this.selectOptions.length > 0){ | |
226 | + this.values = this.getInitialValue().map(value => { | |
227 | + if (typeof value !== 'number' && !value) return null; | |
228 | + return this.getOptionData(value); | |
229 | + }).filter(Boolean); | |
215 | 230 | } |
216 | 231 | |
217 | 232 | if (this.values.length > 0 && this.selectOptions.length === 0){ |
... | ... | @@ -222,7 +237,7 @@ |
222 | 237 | |
223 | 238 | return { |
224 | 239 | prefixCls: prefixCls, |
225 | - values: this.getInitialValue(), | |
240 | + values: [], | |
226 | 241 | dropDownWidth: 0, |
227 | 242 | visible: false, |
228 | 243 | focusIndex: -1, |
... | ... | @@ -400,8 +415,7 @@ |
400 | 415 | getOptionData(value){ |
401 | 416 | const option = this.flatOptions.find(({componentOptions}) => componentOptions.propsData.value === value); |
402 | 417 | if (!option) return null; |
403 | - const textContent = option.componentOptions.children.reduce((str, child) => str + (child.text || ''), ''); | |
404 | - const label = option.componentOptions.propsData.label || textContent || ''; | |
418 | + const label = getOptionLabel(option); | |
405 | 419 | return { |
406 | 420 | value: value, |
407 | 421 | label: label, |
... | ... | @@ -621,14 +635,12 @@ |
621 | 635 | values(now, before){ |
622 | 636 | const newValue = JSON.stringify(now); |
623 | 637 | const oldValue = JSON.stringify(before); |
624 | - const shouldEmitInput = newValue !== oldValue; | |
625 | - | |
638 | + // v-model is always just the value, event with labelInValue === true | |
639 | + const vModelValue = (this.publicValue && this.labelInValue) ? | |
640 | + (this.multiple ? this.publicValue.map(({value}) => value) : this.publicValue.value) : | |
641 | + this.publicValue; | |
642 | + const shouldEmitInput = newValue !== oldValue && vModelValue !== this.value; | |
626 | 643 | if (shouldEmitInput) { |
627 | - // v-model is always just the value, event with labelInValue === true | |
628 | - const vModelValue = this.labelInValue ? | |
629 | - (this.multiple ? this.publicValue.map(({value}) => value) | |
630 | - : | |
631 | - this.publicValue.value) : this.publicValue; | |
632 | 644 | this.$emit('input', vModelValue); // to update v-model |
633 | 645 | this.$emit('on-change', this.publicValue); |
634 | 646 | this.dispatch('FormItem', 'on-form-change', this.publicValue); | ... | ... |
test/unit/specs/select.spec.js
... | ... | @@ -47,7 +47,7 @@ describe('Select.vue', () => { |
47 | 47 | waitForIt( |
48 | 48 | () => { |
49 | 49 | const selectedValueSpan = vm.$el.querySelector('.ivu-select-selected-value'); |
50 | - return selectedValueSpan.textContent === 'Bar'; | |
50 | + return selectedValueSpan && selectedValueSpan.textContent === 'Bar'; | |
51 | 51 | }, |
52 | 52 | () => { |
53 | 53 | const selectedValueSpan = vm.$el.querySelector('.ivu-select-selected-value'); |
... | ... | @@ -121,7 +121,7 @@ describe('Select.vue', () => { |
121 | 121 | waitForIt( |
122 | 122 | () => { |
123 | 123 | const selectedValueSpan = vm.$el.querySelector('.ivu-select-selected-value'); |
124 | - return selectedValueSpan.textContent === 'Bar'; | |
124 | + return selectedValueSpan && selectedValueSpan.textContent === 'Bar'; | |
125 | 125 | }, |
126 | 126 | () => { |
127 | 127 | const placeholderSpan = vm.$el.querySelector('.ivu-select-placeholder'); | ... | ... |