|
360 | 360 | aria-label="Search for option"
|
361 | 361 | >
|
362 | 362 |
|
363 |
| - <button |
364 |
| - v-show="showClearButton" |
365 |
| - :disabled="disabled" |
| 363 | + <button |
| 364 | + v-show="showClearButton" |
| 365 | + :disabled="disabled" |
366 | 366 | @click="clearSelection"
|
367 |
| - type="button" |
368 |
| - class="clear" |
369 |
| - title="Clear selection" |
| 367 | + type="button" |
| 368 | + class="clear" |
| 369 | + title="Clear selection" |
370 | 370 | >
|
371 | 371 | <span aria-hidden="true">×</span>
|
372 | 372 | </button>
|
|
522 | 522 | default: 'label'
|
523 | 523 | },
|
524 | 524 |
|
| 525 | + /** |
| 526 | + * Tells vue-select what key to use when generating option |
| 527 | + * values when each `option` is an object. |
| 528 | + * @type {String} |
| 529 | + */ |
| 530 | + index: { |
| 531 | + type: String, |
| 532 | + default: null |
| 533 | + }, |
| 534 | +
|
525 | 535 | /**
|
526 | 536 | * Callback to generate the label text. If {option}
|
527 | 537 | * is an object, returns option[this.label] by default.
|
| 538 | + * |
| 539 | + * Label text is used for filtering comparison and |
| 540 | + * displaying. If you only need to adjust the |
| 541 | + * display, you should use the `option` and |
| 542 | + * `selected-option` slots. |
| 543 | + * |
528 | 544 | * @type {Function}
|
529 | 545 | * @param {Object || String} option
|
530 | 546 | * @return {String}
|
531 | 547 | */
|
532 | 548 | getOptionLabel: {
|
533 | 549 | type: Function,
|
534 | 550 | default(option) {
|
| 551 | + if( this.index ) { |
| 552 | + option = this.findOptionByIndexValue(option) |
| 553 | + } |
| 554 | +
|
535 | 555 | if (typeof option === 'object') {
|
536 | 556 | if (!option.hasOwnProperty(this.label)) {
|
537 | 557 | return console.warn(
|
|
540 | 560 | 'http://sagalbot.github.io/vue-select/#ex-labels'
|
541 | 561 | )
|
542 | 562 | }
|
543 |
| - if (this.label && option[this.label]) { |
544 |
| - return option[this.label] |
545 |
| - } |
| 563 | + return option[this.label] |
546 | 564 | }
|
547 | 565 | return option;
|
548 | 566 | }
|
|
786 | 804 | if (this.taggable && !this.optionExists(option)) {
|
787 | 805 | option = this.createOption(option)
|
788 | 806 | }
|
789 |
| -
|
| 807 | + if(this.index) { |
| 808 | + if (!option.hasOwnProperty(this.index)) { |
| 809 | + return console.warn( |
| 810 | + `[vue-select warn]: Index key "option.${this.index}" does not` + |
| 811 | + ` exist in options object ${JSON.stringify(option)}.` |
| 812 | + ) |
| 813 | + } |
| 814 | + option = option[this.index] |
| 815 | + } |
790 | 816 | if (this.multiple && !this.mutableValue) {
|
791 | 817 | this.mutableValue = [option]
|
792 | 818 | } else if (this.multiple) {
|
|
808 | 834 | if (this.multiple) {
|
809 | 835 | let ref = -1
|
810 | 836 | this.mutableValue.forEach((val) => {
|
811 |
| - if (val === option || typeof val === 'object' && val[this.label] === option[this.label]) { |
| 837 | + if (val === option || (this.index && val === option[this.index]) || (typeof val === 'object' && val[this.label] === option[this.label])) { |
812 | 838 | ref = val
|
813 | 839 | }
|
814 | 840 | })
|
|
867 | 893 | * @return {Boolean} True when selected | False otherwise
|
868 | 894 | */
|
869 | 895 | isOptionSelected(option) {
|
870 |
| - if (this.multiple && this.mutableValue) { |
871 | 896 | let selected = false
|
872 |
| - this.mutableValue.forEach(opt => { |
873 |
| - if (typeof opt === 'object' && opt[this.label] === option[this.label]) { |
874 |
| - selected = true |
875 |
| - } else if (typeof opt === 'object' && opt[this.label] === option) { |
876 |
| - selected = true |
877 |
| - } |
878 |
| - else if (opt === option) { |
| 897 | + this.valueAsArray.forEach(value => { |
| 898 | + if (typeof value === 'object') { |
| 899 | + selected = this.optionObjectComparator(value, option) |
| 900 | + } else if (value === option || value === option[this.index]) { |
879 | 901 | selected = true
|
880 | 902 | }
|
881 | 903 | })
|
882 | 904 | return selected
|
| 905 | + }, |
| 906 | +
|
| 907 | + /** |
| 908 | + * Determine if two option objects are matching. |
| 909 | + * |
| 910 | + * @param value {Object} |
| 911 | + * @param option {Object} |
| 912 | + * @returns {boolean} |
| 913 | + */ |
| 914 | + optionObjectComparator(value, option) { |
| 915 | + if (this.index && value === option[this.index]) { |
| 916 | + return true |
| 917 | + } else if ((value[this.label] === option[this.label]) || (value[this.label] === option)) { |
| 918 | + return true |
| 919 | + } else if (this.index && value[this.index] === option[this.index]) { |
| 920 | + return true |
883 | 921 | }
|
| 922 | + return false; |
| 923 | + }, |
884 | 924 |
|
885 |
| - return this.mutableValue === option |
| 925 | + /** |
| 926 | + * Finds an option from this.options |
| 927 | + * where option[this.index] matches |
| 928 | + * the passed in value. |
| 929 | + * |
| 930 | + * @param value {Object} |
| 931 | + * @returns {*} |
| 932 | + */ |
| 933 | + findOptionByIndexValue(value) { |
| 934 | + this.options.forEach(_option => { |
| 935 | + if (JSON.stringify(_option[this.index]) === JSON.stringify(value)) { |
| 936 | + value = _option |
| 937 | + } |
| 938 | + }) |
| 939 | + return value |
886 | 940 | },
|
887 | 941 |
|
888 | 942 | /**
|
|
1061 | 1115 | isValueEmpty() {
|
1062 | 1116 | if (this.mutableValue) {
|
1063 | 1117 | if (typeof this.mutableValue === 'object') {
|
1064 |
| - return !Object.keys(this.mutableValue).length |
| 1118 | + return ! Object.keys(this.mutableValue).length |
1065 | 1119 | }
|
1066 |
| - return !this.mutableValue.length |
| 1120 | + return ! this.valueAsArray.length |
1067 | 1121 | }
|
1068 | 1122 |
|
1069 | 1123 | return true;
|
|
1074 | 1128 | * @return {Array}
|
1075 | 1129 | */
|
1076 | 1130 | valueAsArray() {
|
1077 |
| - if (this.multiple) { |
| 1131 | + if (this.multiple && this.mutableValue) { |
1078 | 1132 | return this.mutableValue
|
1079 | 1133 | } else if (this.mutableValue) {
|
1080 | 1134 | return [].concat(this.mutableValue)
|
|
0 commit comments