0

I'm working on a search bar for a project. I have the search bar refer to my data list but I can't get the content to show on screen. I know the array the data list uses is correct because it displays with a regular un-ordered list. I can make a static array show within my datalist but not my dynamic search array.

  <div>
    <!-- Search Bar -->
    <b-form-input
      v-model="text"
      type="text"
      placeholder="Search Courses/Professors"
      list="search-list-id"
      @input="searchInputChanged"
    ></b-form-input>

    <!-- Displayes Filtered List -->
    <li id="my-list-1" v-for="(item, index) in searchArray" :key="index">{{item}}</li>

    <!-- Datalist for Search Bar -->
    <datalist id="search-list-id">
      <!-- This one shows -->
      <option v-for="(size,index) in sizes" :key="index">{{ size }}</option>
      <!-- This one doesn't show. WHY? -->
      <option v-for="(item, index) in searchArray" :key="index">{{item}}</option>
    </datalist>
  </div>
</template>

<script>
import axios from "axios"; // Communicates w/ backend

export default {
  /* eslint-disable no-console */

  name: "Search",
  components: {},
  data() {
    return {
      text: "",
      searchArray: [],
      sizes: ["Small", "Medium", "Large", "Extra Large"]
    };
  },
  methods: {
    searchInputChanged() {...},
    getSearchFromBackend() {...}
  },
  computed: {
    filteredProfessors() {...}
  }
};
</script>

So I can display a static array with data list just fine... My sizes array is visible from the dropdown

But my dynamic list, which I know has the correct array because it display fine in my doesn't show Dynamic array not showing w/in dropdown

I can't seem to figure this one out. Any ideas?

Here is the content of my methods...

methods: {
    searchInputChanged() {
      if (this.text.length > 1) this.getSearchFromBackend();
    },
    getSearchFromBackend() {
      // get the search from the backend
        new Promise((resolve, reject) => {
        this.status = "loading"; // we can show a loading wheel while in this state

        var dataToPassIn = { filter: this.text };
        axios({
          url: "/search/" + this.text,
          data: dataToPassIn,
          method: "GET"
        })
          .then(resp => {
            console.log(resp);
            this.searchArray = resp.data;
            this.status = "success";

            resolve(resp);
          })
          .catch(err => {
            console.log(err);
            this.status = "error";

            reject(err);
          });
      });
    }
  },
  • So where do you assign a new value to `searchArray` (and where do you execute the async request)? Mind providing the whole source file? – Marc Dix Nov 27 '19 at 18:02
  • I assign the value to searchArray within the searchInputChanged method which calls the getSearchFromBackend method which assigns new values to searchArray. I'll update the post to show them – Christian Brock Nov 27 '19 at 18:10
  • Code has been added. – Christian Brock Nov 27 '19 at 18:14
  • And I don't think I execute any async requests unless it's obfuscated by axios. Do I need an async request? – Christian Brock Nov 27 '19 at 18:18
  • As you're making a network request, which can't be instant due to latency and the time that packages need to travel, it's asynchronous. So, as you said, it's kinda obfuscated by axios. Also: I don't see a reason in doing `new Promise` here as axios is doing this, so not doing this would remove a bit of complexity / sources for possible errors. – Marc Dix Nov 27 '19 at 18:23
  • I sat up an example w. a dynamic datalist. Hope it helps to identify your problem. https://codepen.io/mdix/pen/YzzmWPg – Marc Dix Nov 27 '19 at 18:35
  • Thank you. I'm new to axios and a little out of my comfort zone.I'll get rid of the promise. So it just takes time to appear? It seems to near-enough instantaneously update the searchArray shown via an unordered list? – Christian Brock Nov 27 '19 at 18:35
  • Thank you so much Mark. I'll take a look. – Christian Brock Nov 27 '19 at 18:40

1 Answers1

0

Avoid using the same Vue :key for direct children under a single root element:

    <!-- Datalist for Search Bar -->
    <datalist id="search-list-id">
      <!-- prefix key with string 'sizes-' -->
      <option v-for="(size,index) in sizes" :key="'sizes-'+index">{{ size }}</option>
      <!-- prefix key with string 'search-' -->
      <option v-for="(item, index) in searchArray" :key="'search-'+index">{{item}}</option>
    </datalist>

Otherwise Vue is seeing the same key value for two <options> under the one <datalist> element.

You could also simplify this to use the <b-form-datalist> helper component:

    <!-- Datalist for Search Bar -->
    <b-form-datalist id="search-list-id" :options="[...sizes, ...searchArray]">
    </b-form-datalist>
Troy Morehouse
  • 5,320
  • 1
  • 27
  • 38