1

I have a code block here that is 90% working. The idea is that I have an autocomplete (searches via axios with a LIKE condition on the database but I simplified the result set here). When you type in the input, it searches and returns matching results in a dropdown. If you select an option, it replaces the search text in the input with the actual selected value. Then if you click to add another zone it clones the divs with the input.

The issue is that when I create another div and start searching in the input it glitches and then it also triggers the dropdown on both divs (or more if you add more than two). But it doesn't actually allow text to be entered in the newly added zones.

How can I fix this so that each zone actually has it's own input and results dropdown so that I can send something on save that has distinct values for each div?

        new Vue({
          components: {},
          el: "#commonNameDiv",
          data() {
            return {
              searchString: [],
              results: [],
              savedAttributes: [],
              cards: []
            }
          },
          methods: {
            autoComplete() {
              this.results = [];
              console.log(this.searchString);
              if (this.searchString.length > 2) {
                this.results = [
                  {attribute_value:"apple"},
                  {attribute_value:"banane"}
                ]
              }
            },
            saveAttribute(result) {
              this.savedAttributes = [];
              console.log('cool');
              this.savedAttributes.push(result.attribute_value);
              console.log('here is the attribute');
              console.log(this.savedAttributes);
              this.searchString = result.attribute_value;
              this.results = [];
            },
            addCard: function() {
              this.cards.push({
                index: ''
              })
            }
          }
        })
    </script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

<div id="commonNameDiv">
<div class="uk-grid">
                    <div class="uk-width-2-10"  >
                        <input size="4" type="text" name="mapNumber">
                    </div>
                    <div class="uk-width-6-10">
                      <input style="width:100%" type="text" placeholder="what are you looking for?" v-model="searchString" v-on:keyup="autoComplete" class="form-control">
                      <div class="panel-footer componentList" v-if="results.length">
                       <ul class="list-group">
                        <li class="list-group-item" v-for="result in results">
                           <a v-on:click="saveAttribute(result)">{{ result.attribute_value }}</a>
                        </li>
                       </ul>
                      </div>
                    </div>
                    <div class="uk-width-2-10" style="border: 1px solid black; height:50px; width: 50px; margin: 0 auto;" >
                    
                    </div>
                </div>

                <div v-for="(card,index) in cards" class="uk-grid">
                    <div class="uk-width-2-10">
                      <input size="4" type="text" name="mapNumber">
                    </div>
                    <div class="uk-width-6-10">
                      <input style="width:100%" type="text" placeholder="what are you looking for?" v-model="searchString[index]" v-on:keyup="autoComplete" class="form-control">
                      <div class="panel-footer componentList" v-if="results.length">
                        <ul class="list-group">
                          <li class="list-group-item" v-for="result in results">
                            <a v-on:click="saveAttribute(result)">@{{ result.attribute_value }}</a>
                          </li>
                        </ul>
                      </div>
                    </div>
                    <div class="uk-width-2-10" style="border: 1px solid black; height:50px; width: 50px; margin: 0 auto;">

                    </div>
                </div>

                <div style="height: 35px;">
                    
                </div>

                <div>
                    <a v-on:click="addCard">Add another zone</a>
                </div>
</div>

1 Answer 1

1

All your variables and/or properties need to be unique, currently they are not. The easiest way would be in my mind to just store all that you need inside the card object you are using. When you are done, you can just extract the data you need from your array.

Template where we have removed the first div you have, let's just push an empty card object to the array. Our card object will look like this:

{
  index: "",
  value: "" // the end value
  results: [] // the search results will be stored here
}

So in template we use value as v-model for the input and display results for the user to pick their value. Also I suggest you use in all v-for iterations a key. Here I use the index, but that is really not that efficient! But anyway, so the stripped down version of template would look like:

<div v-for="(card, i) in cards" :key="i">
  <div>
    <input
      placeholder="what are you looking for?"
      v-model="card.value"
      v-on:keyup="autoComplete($event, card)"
    >
    <div v-if="card.results.length">
      <ul>
        <li v-for="(result, i) in card.results" :key="i">
          <a v-on:click="saveAttribute(result, card)">@{{ result.attribute_value }}</a>
        </li>
      </ul>
    </div>
  </div>
</div>
<div>
  <a v-on:click="addCard">Add another zone</a>
</div>

The methods would be:

methods: {
  autoComplete(ev, card) {
    if (ev.target.value.length > 2) {
      // here would be actual results...
      card.results = [
        { attribute_value: "apple" },
        { attribute_value: "banane" }
      ];
    }
  },
  saveAttribute(result, card) {
    card.value = result.attribute_value;
  },
  addCard() {
    this.cards.push({
      index: "",
      value: "",
      results: []
    });
  }
}

and lastly, like mentioned, call addCard in a life cycle hook. Here I use created:

created() {
  this.addCard();
}
Sign up to request clarification or add additional context in comments.

4 Comments

Wow, thank you for this very comprehensive answer! One question: Your code for the template shows the secondary card, but not the initial card/div. Would I just leave that as is? IN other words, I want page load to show the initial div there, and then use the v-if loop to add more if the user chooses to add one
Yeah, I though that if you initially push one card to the array when page renderes, that would show immediately when user enters page, so I don't see the need for the intial div at all, since they are the same (? at least looks on quick glance like they are).
That's correct, they are. Ok so I'll just make sure it starts with one in the array then. Thank you so much!
Yes, just make sure that addCard() is called when user enters page. And you are very welcome, glad I could help! :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.