darrenjennings / vue-autosuggest

🔍 Vue autosuggest component.
https://darrenjennings.github.io/vue-autosuggest
MIT License
621 stars 91 forks source link

when input, this compoent $emit input event and this payload is inputevent #74

Closed EtheriousNatsu closed 6 years ago

EtheriousNatsu commented 6 years ago

Relevant code or config

                          <base-auto-suggest
                            :initialValue="data.key"
                            @input="data.key = $event">
                          </base-auto-suggest>
<template>
  <div>
    <vue-autosuggest
      ref="myAutoSuggestRef"
      v-model="localValue"
      v-validate="rules"
      :data-vv-name="name"
      :data-vv-as="alias"
      data-vv-validate-on="input"
      :suggestions="filteredSuggestions"
      :getSuggestionValue="getSuggestionValue"
      :inputProps="inputProps">
      <template slot="header">
          <b-card-header style="">
              Variables
          </b-card-header>
      </template>
      <template slot-scope="{suggestion}">
        <div>
          <div style="margin-bottom: 10px;">
            <var> {{ suggestion.item.key }} </var>
            <b-badge
              class="float-right"
              variant="danger"
              v-if="suggestion.item.overwrite">
              OVERRIDDEN
            </b-badge>
          </div>
          <dl class="row">
            <dt class="col-md-3 flex-wrap">
              <small class="text-muted">Def:</small>
            </dt>
            <dd 
              class="col-md-9 text-truncate"
              style="padding-left: 0px;">
              <small>
                <span>
                  {{ suggestion.item.fromType }}
                  (
                  <i>{{ suggestion.item.fromName }}</i>
                  )
                </span>
              </small>
            </dd>
            <dt class="col-md-3 flex-wrap">
              <small class="text-muted">Val:</small>
            </dt>
            <dd 
              class="col-md-9"
              style="padding-left: 0px;">
              <small>
                <code> {{ suggestion.item.value }} </code>
              </small>
            </dd>
          </dl>
        </div>
      </template>
    </vue-autosuggest>
    <p v-if="errors.first(scope + '.' + name)">
      <span style="color: red;">
        {{errors.first(scope + '.' +name)}}
      </span>
    </p>
  </div>
</template>
import { VueAutosuggest } from "vue-autosuggest";

import { clone } from "@/config/utils";

export default {
  name: "BaseAutoSuggest",
  components: {
    VueAutosuggest
  },
  inject: ["$validator"], // inject parent validator
  props: {
    initialValue: {
      type: String,
      default: ""
    },
    rules: {
      type: String,
      default: ""
    },
    name: {
      type: String,
      default: "autosuggest"
    },
    alias: {
      type: String
    },
    scope: {
      type: String,
      default: "autosuggest"
    }
  },
  data() {
    return {
      filteredSuggestions: [],
      localValue: ""
    };
  },
  computed: {
    evironment() {
      return this.$store.getters.getEnvironment(this.$store.state.env);
    },
    test() {
      return this.$store.getters.getTest(this.$route.params.testId);
    },
    variables() {
      // test variables
      const testVars = clone(this.test.variables);

      testVars.forEach(v => {
        v.fromType = "Test";
        v.fromName = this.test.name;
      });

      // environment variables
      const envVars = clone(this.evironment.variables);
      envVars.forEach(v => {
        v.fromType = "Evironment";
        v.fromName = this.evironment.name;

        // 看是否被test中变量覆盖
        if (
          testVars.some(testV => {
            return testV.key === v.key;
          })
        ) {
          v.overwrite = true;
        }
      });

      const totalVars = testVars.concat(envVars);

      return totalVars;
    },
    inputProps() {
      return {
        id: "autosuggest__input",
        onInputChange: this.fetchResults,
        initialValue: this.initialValue,
        name: this.name,
        class: this.stateClass
      };
    },
    stateClass() {
      return this.errors.has(this.scope + "." + this.name) ? "is-invalid" : "";
    }
  },
  watch: {
    initialValue(newVal) {
      this.$refs.myAutoSuggestRef.searchInput = newVal;
    },
    localValue(newVal) {
      this.$emit("input", newVal);
    }
  },
  methods: {
    fetchResults(text) {
      this.setLocalValue(text);

      if (!text.includes("${")) {
        this.filteredSuggestions = [];
        return;
      }

      // 只能匹配单个正则表达式,例如 ${xxxx,则匹配为 xxxx,如果为${,则匹配为 "",
      const pattern = /\$\{(.*)\}?/;
      const matched = pattern.exec(text)[1];

      let filteredData = null;
      if (matched === "") {
        filteredData = this.variables;
      } else {
        filteredData = this.variables.filter(variable => {
          return variable.key.includes(matched);
        });
      }

      this.filteredSuggestions = [{ data: filteredData }];
    },
    getSuggestionValue(suggestion) {
      const variable = suggestion.item;
      const replaced = "${" + variable.key + "}";

      this.setLocalValue(this.localValue.replace(/\$\{(.*)\}?/, replaced));

      return this.localValue;
    },
    setLocalValue(val) {
      this.localValue = val;
    }
  }
};

What you did: I input character a

What happened: this localvalue is inputevent

image

Reproduction repository:

Problem description: I think maybe its v-model cause.

Suggested solution:

darrenjennings commented 6 years ago

Currently vue-autosuggest cannot bind the v-model that you put on the <vue-autosuggest ..> tag in this way, so you will get both the input event emit from vue-autosuggest in addition to the v-model event emitter in base-auto-suggest through it's v-model. You can get around it by using v-validate.disable="rules" and triggering the validation in fetchResults. I've updated the codesandbox to do this if you want to look there for inspiration. Another idea is to tell v-validate when to emit, but it wasn't working for me if you are curious to try it https://baianat.github.io/vee-validate/guide/events.html#changing-events-per-field

Let me know if this works for you.

EtheriousNatsu commented 6 years ago

yes ,thank you, it works. I remove v-model , and disable vee-validator auto, then triggering the validation in fetchResults.