| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120 |
- <template>
- <div class="dropdown" :class="{'open': open}">
- <div class="input-group">
- <input type="text" class="form-control" v-model="searchText" @input="searchChanged">
- <div class="form-group-append">
- <a class="toggle input-group-text bg-primary text-light" @mousedown.prevent @click="setOpen(!open)">
- <span class="arrow-up">▲</span>
- <span class="arrow-down">▼</span>
- </a>
- </div>
- </div>
- <ul class="suggestion-list list-unstyled">
- <li v-for="(suggestion,index) in matches" :key="index"
- @mousedown.prevent
- @click="suggestionSelected(suggestion)"
- >
- {{ suggestion[1] }}
- </li>
- </ul>
- </div>
- </template>
- <script>
- export default {
- props: {
- value: null,
- // An object with the following format
- // {
- // key: value,
- // key: value,
- // }
- options: {
- type: Object,
- required: true
- },
- allowCustom: {
- type: Boolean,
- default: false
- }
- },
- data () {
- return {
- searchText: '',
- selectedOption: null,
- open: false,
- // allows for checking whether button was clicked or text was typed.
- // If button was clicked, we show all options without having to clear
- // out any searchText that was autofilled when page loaded.
- isSearching: false
- }
- },
- computed: {
- matches () {
- // If button was clicked, show all options, if typing, filter
- // options based on searchText
- return Object.entries(this.options).filter((option) => {
- var optionText = option[1].toUpperCase()
- if (this.isSearching) {
- return optionText.match(this.searchText.toUpperCase())
- }
- else {
- return optionText.match('')
- }
- })
- }
- },
- methods: {
- // if button is clicked, show all options
- setOpen (isOpen) {
- this.open = isOpen
- this.isSearching = false
- },
- // if typing in the box, start filtering options
- searchChanged () {
- if (!this.open) {
- this.open = true
- }
- if (!this.isSearching) {
- this.isSearching = true
- }
- // If custom values are allowed, emits {id: 'custom', name: searchtext}
- if (this.allowCustom) {
- this.$emit('input', {'id': 'custom', 'name': this.searchText})
- }
- },
- // emits { id: suggestion_id, name: suggestion_name} to v-model when
- // a suggestion is selected
- suggestionSelected (suggestion) {
- this.open = false
- this.searchText = suggestion[1]
- this.$emit('input', { 'id': suggestion[0], 'name': suggestion[1]})
- },
- updateComponentWithValue(newValue) {
- if (this.allowCustom) {
- this.searchText = this.value.name
- }
- else {
- if (newValue.id > -1) {
- // Find the matching text for the supplied option value
- for (var id in this.options) {
- if (this.options.hasOwnProperty(id)) {
- if (this.options[id] === this.options[newValue.id]) {
- this.searchText = this.options[id]
- }
- }
- }
- }
- }
- }
- },
- mounted () {
- this.updateComponentWithValue(this.value)
- },
- watch: {
- value: function (newValue) {
- this.updateComponentWithValue(newValue)
- }
- }
- }
- </script>
|