Search code examples
vue.jsvue-multiselect

How to update the displayed available options in Vue Multiselect after searching


I have a vue multiselect with a custom search function. When I enter text to search, it updates the available options, but the available options displayed to the user don't change until they select one of the options. What do I need to do to get the multiselect options to refresh when you search the available options?

<v-row 
    v-for="(filter, idx) in campaign.filters.selected_filters"
      align="center"
      :key="idx"
      style="margin-top: 8px"
    >  
      <v-col cols="4" style="padding-top:25px"> <!-- First select -->
        <vue-multiselect
            v-model="filter.column"
            :options="temp_selected_filters[idx].availableColumns"
            @input="filterSelectionChanged(filter.column, idx)"
            :multiple="false"
            :close-on-select="true"
            :clear-on-select="false"
            :preserve-search="true"
            placeholder="Field"
            :show-labels="false"
            :internal-search="false"
            @search-change="(query) => searchTextChange(idx, query)"
            style="width:100%">
            
              <!-- Use the slot to display only the "text" part -->
              <template slot="option" slot-scope="{ option }">
                {{ getColumnObject(option).name }}
              </template>
            
              <!-- Use the slot to display only the "text" part of the selected item -->
              <template slot="singleLabel" slot-scope="{ option }">
                {{ getColumnObject(option).name }}
              </template>
            
        </vue-multiselect>
    // ... more items

Here is the search function:


searchTextChange(index, query) {
            this.temp_selected_filters[index].availableColumns = [];
            this.availableColumns.forEach(item => {
                const name = this.getColumnObject(item).name;
                if (name.toLowerCase().includes(query)) {
                    this.temp_selected_filters[index].availableColumns.push(item);
                }
            });
            this.temp_selected_filters[index].searchText = query;
        },

And here is the filterSelectionChanged function:

        filterSelectionChanged(column, index) {
            if (this.temp_selected_filters[index]) {
                const prev_selected_column = this.temp_selected_filters[index].column;
                // Either they unselected a previously selected filter, or added a new filter without selecting a column and typed in the value, or they changed the column and the new type is not the same as the old column type
                if ((!column && this.available_filters[prev_selected_column].type != 'string')
                    || (column &&
                        ((!prev_selected_column && this.available_filters[column].type != 'string')
                            || (prev_selected_column && this.available_filters[column].type != this.available_filters[prev_selected_column].type)))
                ) {
                    this.campaign.filters.selected_filters[index].value = '';
                }
            }
            this.temp_selected_filters[index].column = column;
            if (!this.getOperators(column).includes(this.campaign.filters.selected_filters[index].operator)) { // Reset the operator if user selects a column, picks an operator, then changes the column and the new column doesn't include the previously selected operator.
                this.campaign.filters.selected_filters[index].operator = '';
            }
        },

After entering search text, here is what temp_selected_filters might look like:

"0": {
        "column": null,
        "searchText": "email",
        "availableColumns": [
            "email",
            "manager_email",
            "personal_email"
        ]
    },
"1": {
        "column": "address",
        "searchText": "addr",
        "availableColumns": [
            "address",
            "work_address"
        ]
    },

Solution

  • I figured it out. I need to call forceUpdate after the data in temp_selected_filters[idx].availableColumns changed:

    searchTextChange(index, query) {
        this.temp_selected_filters[index].availableColumns = [];
        this.availableColumns.forEach(item => {
            const name = this.getColumnObject(item).name;
            if (name.toLowerCase().includes(query)) {
               this.temp_selected_filters[index].availableColumns.push(item);
            }
        });
        this.temp_selected_filters[index].searchText = query;
        this.$forceUpdate();
    },