|
174 | 174 | <div class="dropdown v-select" :class="dropdownClasses">
|
175 | 175 | <div ref="toggle" @mousedown.prevent="toggleDropdown" class="dropdown-toggle clearfix" type="button">
|
176 | 176 |
|
177 |
| - <span class="selected-tag" v-for="option in valueAsArray" v-bind:key="index"> |
| 177 | + <span class="selected-tag" v-for="option in valueAsArray" v-bind:key="option.index"> |
178 | 178 | {{ getOptionLabel(option) }}
|
179 | 179 | <button v-if="multiple" @click="select(option)" type="button" class="close">
|
180 | 180 | <span aria-hidden="true">×</span>
|
|
199 | 199 | :style="{ width: isValueEmpty ? '100%' : 'auto' }"
|
200 | 200 | >
|
201 | 201 |
|
202 |
| - <i ref="open-indicator" role="presentation" class="open-indicator"></i> |
| 202 | + <i ref="openIndicator" role="presentation" class="open-indicator"></i> |
203 | 203 |
|
204 | 204 | <slot name="spinner">
|
205 |
| - <div class="spinner" v-show="loading">Loading...</div> |
| 205 | + <div class="spinner" v-show="showLoading">Loading...</div> |
206 | 206 | </slot>
|
207 | 207 | </div>
|
208 | 208 |
|
209 |
| - <ul ref="dropdown-menu" v-show="open" :transition="transition" class="dropdown-menu" :style="{ 'max-height': maxHeight }"> |
| 209 | + <ul ref="dropdownMenu" v-show="open" :transition="transition" class="dropdown-menu" :style="{ 'max-height': maxHeight }"> |
210 | 210 | <li v-for="(option, index) in filteredOptions" v-bind:key="index" :class="{ active: isOptionSelected(option), highlight: index === typeAheadPointer }" @mouseover="typeAheadPointer = index">
|
211 | 211 | <a @mousedown.prevent="select(option)">
|
212 | 212 | {{ getOptionLabel(option) }}
|
|
236 | 236 | props: {
|
237 | 237 | /**
|
238 | 238 | * Contains the currently selected value. Very similar to a
|
239 |
| - * `value` attribute on an <input>. In most cases, you'll want |
240 |
| - * to set this as a two-way binding, using :value.sync. However, |
241 |
| - * this will not work with Vuex, in which case you'll need to use |
242 |
| - * the onChange callback property. |
| 239 | + * `value` attribute on an <input>. You can listen for changes |
| 240 | + * using 'change' event using v-on |
243 | 241 | * @type {Object||String||null}
|
244 | 242 | */
|
245 | 243 | value: {
|
|
344 | 342 | }
|
345 | 343 | },
|
346 | 344 |
|
347 |
| - /** |
348 |
| - * An optional callback function that is called each time the selected |
349 |
| - * value(s) change. When integrating with Vuex, use this callback to trigger |
350 |
| - * an action, rather than using :value.sync to retreive the selected value. |
351 |
| - * @type {Function} |
352 |
| - * @default {null} |
353 |
| - */ |
354 |
| - onChange: Function, |
355 |
| -
|
356 | 345 | /**
|
357 | 346 | * Enable/disable creating options from searchInput.
|
358 | 347 | * @type {Boolean}
|
|
379 | 368 | createOption: {
|
380 | 369 | type: Function,
|
381 | 370 | default: function (newOption) {
|
382 |
| - if (typeof this.options[0] === 'object') { |
| 371 | + if (typeof this.actualOptions[0] === 'object') { |
383 | 372 | return {[this.label]: newOption}
|
384 | 373 | }
|
385 | 374 | return newOption
|
|
399 | 388 | data() {
|
400 | 389 | return {
|
401 | 390 | search: '',
|
402 |
| - open: false |
| 391 | + open: false, |
| 392 | + actualValue: null, |
| 393 | + actualOptions: [], |
| 394 | + showLoading: false |
403 | 395 | }
|
404 | 396 | },
|
405 | 397 |
|
406 | 398 | watch: {
|
407 |
| - value(val, old) { |
| 399 | + actualValue(val, old) { |
408 | 400 | if (this.multiple) {
|
409 |
| - this.onChange ? this.onChange(val) : null |
| 401 | + this.$emit('change', val) |
410 | 402 | } else {
|
411 |
| - this.onChange && val !== old ? this.onChange(val) : null |
| 403 | + if(val !== old) { |
| 404 | + this.$emit('change', val) |
| 405 | + } |
412 | 406 | }
|
413 | 407 | },
|
414 |
| - options() { |
| 408 | + actualOptions() { |
415 | 409 | if (!this.taggable && this.resetOnOptionsChange) {
|
416 |
| - this.$set('value', this.multiple ? [] : null) |
| 410 | + this.actualValue = this.multiple ? [] : null |
417 | 411 | }
|
418 |
| - }, |
419 |
| - multiple(val) { |
420 |
| - this.$set('value', val ? [] : null) |
421 | 412 | }
|
422 | 413 | },
|
423 | 414 |
|
|
436 | 427 | option = this.createOption(option)
|
437 | 428 |
|
438 | 429 | if (this.pushTags) {
|
439 |
| - this.options.push(option) |
| 430 | + this.actualOptions.push(option) |
440 | 431 | }
|
441 | 432 | }
|
442 | 433 |
|
443 | 434 | if (this.multiple) {
|
444 |
| - if (!this.value) { |
445 |
| - this.$set('value', [option]) |
| 435 | + if (!this.actualValue) { |
| 436 | + this.actualValue = [option] |
446 | 437 | } else {
|
447 |
| - this.value.push(option) |
| 438 | + this.actualValue.push(option) |
448 | 439 | }
|
449 | 440 | } else {
|
450 |
| - this.value = option |
| 441 | + this.actualValue = option |
451 | 442 | }
|
452 | 443 | }
|
453 | 444 |
|
|
462 | 453 | deselect(option) {
|
463 | 454 | if (this.multiple) {
|
464 | 455 | let ref = -1
|
465 |
| - this.value.forEach((val) => { |
| 456 | + this.actualValue.forEach((val) => { |
466 | 457 | if (val === option || typeof val === 'object' && val[this.label] === option[this.label]) {
|
467 | 458 | ref = val
|
468 | 459 | }
|
469 | 460 | })
|
470 |
| - var index = this.value.indexOf(ref) |
471 |
| - this.value.splice(index, 1) |
| 461 | + var index = this.actualValue.indexOf(ref) |
| 462 | + this.actualValue.splice(index, 1) |
472 | 463 | } else {
|
473 |
| - this.value = null |
| 464 | + this.actualValue = null |
474 | 465 | }
|
475 | 466 | },
|
476 | 467 |
|
|
512 | 503 | * @return {Boolean} True when selected || False otherwise
|
513 | 504 | */
|
514 | 505 | isOptionSelected(option) {
|
515 |
| - if (this.multiple && this.value) { |
| 506 | + if (this.multiple && this.actualValue) { |
516 | 507 | let selected = false
|
517 |
| - this.value.forEach(opt => { |
| 508 | + this.actualValue.forEach(opt => { |
518 | 509 | if (typeof opt === 'object' && opt[this.label] === option[this.label]) {
|
519 | 510 | selected = true
|
520 | 511 | } else if (opt === option) {
|
|
524 | 515 | return selected
|
525 | 516 | }
|
526 | 517 |
|
527 |
| - return this.value === option |
| 518 | + return this.actualValue === option |
528 | 519 | },
|
529 | 520 |
|
530 | 521 | /**
|
|
546 | 537 | * @return {this.value}
|
547 | 538 | */
|
548 | 539 | maybeDeleteValue() {
|
549 |
| - if (!this.$refs.search.value.length && this.value) { |
550 |
| - return this.multiple ? this.value.pop() : this.$set('value', null) |
| 540 | + if (!this.$refs.search.value.length && this.actualValue) { |
| 541 | + return this.multiple ? this.actualValue.pop() : this.actualValue = null |
551 | 542 | }
|
552 | 543 | },
|
553 | 544 |
|
554 | 545 | /**
|
555 | 546 | * Determine if an option exists
|
556 |
| - * within this.options array. |
| 547 | + * within this.actualOptions array. |
557 | 548 | *
|
558 | 549 | * @param {Object || String} option
|
559 | 550 | * @return {boolean}
|
560 | 551 | */
|
561 | 552 | optionExists(option) {
|
562 | 553 | let exists = false
|
563 | 554 |
|
564 |
| - this.options.forEach(opt => { |
| 555 | + this.actualOptions.forEach(opt => { |
565 | 556 | if (typeof opt === 'object' && opt[this.label] === option) {
|
566 | 557 | exists = true
|
567 | 558 | } else if (opt === option) {
|
|
583 | 574 | return {
|
584 | 575 | open: this.open,
|
585 | 576 | searchable: this.searchable,
|
586 |
| - loading: this.loading |
| 577 | + loading: this.showLoading |
587 | 578 | }
|
588 | 579 | },
|
589 | 580 |
|
|
607 | 598 | * @return {array}
|
608 | 599 | */
|
609 | 600 | filteredOptions() {
|
610 |
| - let options = this.$options.filters.filterBy?this.$options.filters.filterBy(this.options, this.search):this.options |
| 601 | + let options = this.$options.filters.filterBy?this.$options.filters.filterBy(this.actualOptions, this.search):this.actualOptions |
611 | 602 | if (this.taggable && this.search.length && !this.optionExists(this.search)) {
|
612 | 603 | options.unshift(this.search)
|
613 | 604 | }
|
|
619 | 610 | * @return {Boolean}
|
620 | 611 | */
|
621 | 612 | isValueEmpty() {
|
622 |
| - if (this.value) { |
623 |
| - if (typeof this.value === 'object') { |
624 |
| - return !Object.keys(this.value).length |
| 613 | + if (this.actualValue) { |
| 614 | + if (typeof this.actualValue === 'object') { |
| 615 | + return !Object.keys(this.actualValue).length |
625 | 616 | }
|
626 |
| - return !this.value.length |
| 617 | + return !this.actualValue.length |
627 | 618 | }
|
628 | 619 |
|
629 | 620 | return true;
|
|
635 | 626 | */
|
636 | 627 | valueAsArray() {
|
637 | 628 | if (this.multiple) {
|
638 |
| - return this.value |
639 |
| - } else if (this.value) { |
640 |
| - return [this.value] |
| 629 | + return this.actualValue |
| 630 | + } else if (this.actualValue) { |
| 631 | + return [this.actualValue] |
641 | 632 | }
|
642 | 633 |
|
643 | 634 | return []
|
644 | 635 | }
|
| 636 | + }, |
| 637 | + created: function() { |
| 638 | + this.actualValue = this.value |
| 639 | + this.actualOptions = this.options.slice(0) |
| 640 | + this.showLoading = this.loading |
645 | 641 | }
|
646 | 642 |
|
647 | 643 | }
|
|
0 commit comments