Autocompletar - seleccione la opción con el clic del ratón - vuejs

votos
0

Hace algún tiempo, he creado un componente de autocompletar en vue para un proyecto en el que estoy involucrado.

Pero hoy he detectado un pequeño fallo.

Cuando selecciono la opción que quiera con el clic del ratón, la opción no consigue transmitir, como se puede ver en el console.log ()que se encuentra en el ejemplo. Si hago clic en otra opción de nuevo, lo que aparecerá en console.log ()la opción seleccionada previamente.

Si pongo una setTimeout( () => {}, 200)que ya se detecta y emite la opción, pero creo que no es la mejor solución para este caso.

¿Cualquier sugerencia?

ejemplo

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>

Publicado el 14/02/2020 a las 00:00
fuente por usuario
En otros idiomas...                            


2 respuestas

votos
1

Estaba utilizando onBlur evento, pero su despedido cuando se hace clic fuera y antes de receptor de elementos del onclick, por lo que el valor no se ha actualizado.

Utilice onchange evento para capturar datos si usuario escribe nada en el método de entrada y llamar onchange () dentro 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>

Respondida el 14/02/2020 a las 00:25
fuente por usuario

votos
1

blures el evento incorrecto utilizar aquí, y creo que estás más de complicarla. Simplemente llame a su emiten setResult:

setResult(result, i) {
      this.arrowCounter = i;
      this.search = result;
      this.isOpen = false;     
      this.$emit("input", this.search);
    },
Respondida el 14/02/2020 a las 00:44
fuente por usuario

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