Autocomplete - sélectionnez l'option avec le clic de la souris - vuejs

voix
0

Il y a quelque temps que je créé un élément de saisie semi-automatique en vue d'un projet dans lequel je suis impliqué.

Mais aujourd'hui, je détecté un petit bug.

Lorsque je sélectionne l'option que je veux avec le clic de la souris, l'option ne soit pas transmis, comme vous pouvez le voir dans le console.log ()qui est dans l'exemple. Si je clique sur une autre option à nouveau, ce qui apparaîtra dans console.log ()est l'option sélectionnée précédemment.

Si je mets un setTimeout( () => {}, 200)détecte déjà et émette l'option, mais je pense que ce n'est pas la meilleure solution pour ce cas.

Toute suggestion?

exemple

const Autocomplete = {
  name: autocomplete,
  template: #autocomplete,
  props: {
    items: {
      type: Array,
      required: false,
      default: () => Array(150).fill().map((_, i) => `Fruit ${i+1}`)
    },
    isAsync: {
      type: Boolean,
      required: false,
      default: false
    }
  },

  data() {
    return {
      isOpen: false,
      results: [],
      search: ,
      isLoading: false,
      arrowCounter: 0
    };
  },

  methods: {
    onChange() {
      console.log( this.search)
      // Let's warn the parent that a change was made
      this.$emit(input, this.search);
    },
    setResult(result, i) {
      this.arrowCounter = i;
      this.search = result;
      this.isOpen = false;
    },
    showAll() {
      this.isOpen = !this.isOpen;
			(this.isOpen) ? this.results = this.items : this.results = [];
    },
  },
  computed: {
      filterResults() {
      // first uncapitalize all the things
      this.results = this.items.filter(item => {
        return item.toLowerCase().indexOf(this.search.toLowerCase()) > -1;
      });
      
     
      return this.results;
    },
  },
  watch: {
    items: function(val, oldValue) {
      // actually compare them
      if (val.length !== oldValue.length) {
        this.results = val;
        this.isLoading = false;
      }
    }
  },
  mounted() {
    document.addEventListener(click, this.handleClickOutside);
  },
  destroyed() {
    document.removeEventListener(click, this.handleClickOutside);
  }
};

new Vue({
  el: #app,
  name: app,
  components: {
    autocomplete: Autocomplete
  }
});
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  color: #2c3e50;
}

.autocomplete {
  position: relative;
  width: 130px;
}

.autocomplete-results {
  padding: 0;
  margin: 0;
  border: 1px solid #eeeeee;
  height: 120px;
  overflow: auto;
  width: 100%;
}

.autocomplete-result {
  list-style: none;
  text-align: left;
  padding: 4px 2px;
  cursor: pointer;
}

.autocomplete-result.is-active,
.autocomplete-result:hover {
  background-color: #4aae9b;
  color: white;
}
<script src=https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js></script>
<div id=app>
  <autocomplete />

</div>

<script type=text/x-template id=autocomplete>
  <div class=autocomplete>
    <input type=text @blur=onChange v-model=search  @click=showAll />
    <ul id=autocomplete-results v-show=isOpen ref=scrollContainer class=autocomplete-results>
      <li class=loading v-if=isLoading>
        Loading results...
      </li>
      <li ref=options v-else v-for=(result, i) in filterResults :key=i @click=setResult(result, i) class=autocomplete-result :class={ 'is-active': i === arrowCounter }>
        {{ result }}
      </li>
    </ul>

  </div>
</script>

Créé 14/02/2020 à 00:00
source utilisateur
Dans d'autres langues...                            


2 réponses

voix
1

Vous utilisiez événement onblur, mais son mis le feu lorsque vous cliquez sur l'extérieur et avant l'écouteur d'élément du onclick, de sorte que la valeur n'a pas été mis à jour.

Utilisez onchange événement pour capturer des données si les types d'utilisateurs quelque chose dans l'entrée et appeler la méthode onChange () à l'intérieur setResult ().

const Autocomplete = {
  name: "autocomplete",
  template: "#autocomplete",
  props: {
    items: {
      type: Array,
      required: false,
      default: () => Array(150).fill().map((_, i) => `Fruit ${i+1}`)
    },
    isAsync: {
      type: Boolean,
      required: false,
      default: false
    }
  },

  data() {
    return {
      isOpen: false,
      results: [],
      search: "",
      isLoading: false,
      arrowCounter: 0
    };
  },

  methods: {
    onChange() {
      console.log( this.search)
      // Let's warn the parent that a change was made
      this.$emit("input", this.search);
    },
    setResult(result, i) {
      this.arrowCounter = i;
      this.search = result;
      this.isOpen = false;
      // Fire onChange, because it won't do it on blur
      this.onChange();
    },
    showAll() {
      this.isOpen = !this.isOpen;
			(this.isOpen) ? this.results = this.items : this.results = [];
    },
  },
  computed: {
      filterResults() {
      // first uncapitalize all the things
      this.results = this.items.filter(item => {
        return item.toLowerCase().indexOf(this.search.toLowerCase()) > -1;
      });
      
     
      return this.results;
    },
  },
  watch: {
    items: function(val, oldValue) {
      // actually compare them
      if (val.length !== oldValue.length) {
        this.results = val;
        this.isLoading = false;
      }
    }
  },
  mounted() {
    document.addEventListener("click", this.handleClickOutside);
  },
  destroyed() {
    document.removeEventListener("click", this.handleClickOutside);
  }
};

new Vue({
  el: "#app",
  name: "app",
  components: {
    autocomplete: Autocomplete
  }
});
#app {
  font-family: "Avenir", Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  color: #2c3e50;
}

.autocomplete {
  position: relative;
  width: 130px;
}

.autocomplete-results {
  padding: 0;
  margin: 0;
  border: 1px solid #eeeeee;
  height: 120px;
  overflow: auto;
  width: 100%;
}

.autocomplete-result {
  list-style: none;
  text-align: left;
  padding: 4px 2px;
  cursor: pointer;
}

.autocomplete-result.is-active,
.autocomplete-result:hover {
  background-color: #4aae9b;
  color: white;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script>
<div id="app">
  <autocomplete />

</div>

<script type="text/x-template" id="autocomplete">
  <div class="autocomplete">
    <input type="text" @change="onChange" v-model="search"  @click="showAll" />
    <ul id="autocomplete-results" v-show="isOpen" ref="scrollContainer" class="autocomplete-results">
      <li class="loading" v-if="isLoading">
        Loading results...
      </li>
      <li ref="options" v-else v-for="(result, i) in filterResults" :key="i" @click="setResult(result, i)" class="autocomplete-result" :class="{ 'is-active': i === arrowCounter }">
        {{ result }}
      </li>
    </ul>

  </div>
</script>

Créé 14/02/2020 à 00:25
source utilisateur

voix
1

blurest le mauvais événement à utiliser ici, et je pense que vous êtes sur le compliquer. Il suffit d' appeler votre emiten setResult:

setResult(result, i) {
      this.arrowCounter = i;
      this.search = result;
      this.isOpen = false;     
      this.$emit("input", this.search);
    },
Créé 14/02/2020 à 00:44
source utilisateur

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more