javascript - Vue component $emit firing twice - Stack Overflow

I'm recently trying to reutilize my Vue ponents in some real-world application to remove unnecessa

I'm recently trying to reutilize my Vue ponents in some real-world application to remove unnecessary duplicates and clutter with <divs>.

But I'm having trouble in doing so. After hours I managed to "acplish" it, but now the event fires twice and I don't know exactly why.

I've made a basic setup to show the problem:

Vueponent("bs-select",{
template:
 `<div class="form-group">
    <label class="control-label">{{ label }}</label>
    <select2
      ref="select2control"
      :options="options"
      :value="value"
      @input="chosenOption"
    ></select2>
  </div>`,
  props: ["value", "label", "options"],
  methods: {
    chosenOption(val) {
      this.$emit("input", val);
    }
  }
});

Vueponent("select2",{
template:
 `<select :value="value" style="width: 100%">
    <option value="" selected disabled>Choose...</option>
    <option v-if="!options">{{ value }}</option>
    <option v-for="option in options" :value="option.value">{{ option.text }}</option>
  </select>`,
  props: ["value", "options"],
  mounted: function() {
    const vm = this;

    $(vm.$el)
      .select2()
      .on("change", function() {
        console.log("CHANGE", vm.$el.value);
        vm.$emit("input", vm.$el.value);
      });
  },
  watch: {
    value: function(val) {
      $(this.$el)
        .val(val)
        .trigger("change");
    }
  }
});

new Vue({
  el: "#app",
  data: {
    test: "bug",
    options: [
    {
      value: "hello",
      text: "Hello"
    },
    {
      value: "bug",
      text: "Bug"
    }
    ]
  }
})
* {
  font-family: Arial;
  font-size: 10px;
}

div {
}
<script src=".1.1/jquery.min.js"></script>
<script src=".0.5/js/select2.min.js"></script>
<link href=".0.5/css/select2.min.css" rel="stylesheet"/>
<script src=".5.17/vue.min.js"></script>

<div id="app">
  <bs-select v-model="test" :options="options"></bs-select>
  <br><br>
  <button @click="test = 'bug'">
  Set 'test' variable to 'bug' (Two-way check)
  </button>
{{ test }}
</div>

<div>
Event is firing twice in console...
</div>

I'm recently trying to reutilize my Vue ponents in some real-world application to remove unnecessary duplicates and clutter with <divs>.

But I'm having trouble in doing so. After hours I managed to "acplish" it, but now the event fires twice and I don't know exactly why.

I've made a basic setup to show the problem:

Vue.ponent("bs-select",{
template:
 `<div class="form-group">
    <label class="control-label">{{ label }}</label>
    <select2
      ref="select2control"
      :options="options"
      :value="value"
      @input="chosenOption"
    ></select2>
  </div>`,
  props: ["value", "label", "options"],
  methods: {
    chosenOption(val) {
      this.$emit("input", val);
    }
  }
});

Vue.ponent("select2",{
template:
 `<select :value="value" style="width: 100%">
    <option value="" selected disabled>Choose...</option>
    <option v-if="!options">{{ value }}</option>
    <option v-for="option in options" :value="option.value">{{ option.text }}</option>
  </select>`,
  props: ["value", "options"],
  mounted: function() {
    const vm = this;

    $(vm.$el)
      .select2()
      .on("change", function() {
        console.log("CHANGE", vm.$el.value);
        vm.$emit("input", vm.$el.value);
      });
  },
  watch: {
    value: function(val) {
      $(this.$el)
        .val(val)
        .trigger("change");
    }
  }
});

new Vue({
  el: "#app",
  data: {
    test: "bug",
    options: [
    {
      value: "hello",
      text: "Hello"
    },
    {
      value: "bug",
      text: "Bug"
    }
    ]
  }
})
* {
  font-family: Arial;
  font-size: 10px;
}

div {
}
<script src="https://ajax.googleapis./ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare./ajax/libs/select2/4.0.5/js/select2.min.js"></script>
<link href="https://cdnjs.cloudflare./ajax/libs/select2/4.0.5/css/select2.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare./ajax/libs/vue/2.5.17/vue.min.js"></script>

<div id="app">
  <bs-select v-model="test" :options="options"></bs-select>
  <br><br>
  <button @click="test = 'bug'">
  Set 'test' variable to 'bug' (Two-way check)
  </button>
{{ test }}
</div>

<div>
Event is firing twice in console...
</div>

I also Googled a lot and came to no conclusion on why this happens and/or how to fix this issue.

Any help is greatly appreciated.

Share Improve this question edited Nov 8, 2018 at 12:49 Fusseldieb asked Nov 8, 2018 at 11:46 FusseldiebFusseldieb 1,3743 gold badges20 silver badges47 bronze badges
Add a ment  | 

3 Answers 3

Reset to default 1

After asking some of my friends, one figured it out that the "change" trigger must be in beforeUpdate.

So, the solved code looks like this:

Vue.ponent("bs-select",{
template:
 `<div class="form-group">
    <label class="control-label">{{ label }}</label>
    <select2
      ref="select2control"
      :options="options"
      :value="value"
      @input="chosenOption"
    ></select2>
  </div>`,
  props: ["value", "label", "options"],
  methods: {
    chosenOption(val) {
      this.$emit("input", val);
    }
  }
});

Vue.ponent("select2",{
template:
 `<select :value="value" style="width: 100%">
    <option value="" selected disabled>Choose...</option>
    <option v-if="!options">{{ value }}</option>
    <option v-for="option in options" :value="option.value">{{ option.text }}</option>
  </select>`,
  props: ["value", "options"],
  mounted: function() {
    const vm = this;

    $(vm.$el)
      .select2()
      .on("change", function() {
        console.log("CHANGE", vm.$el.value);
        vm.$emit("input", vm.$el.value);
      });
  },
    beforeUpdate() {
    $(this.$el).val(this.value).trigger('change.select2')
  }
});

new Vue({
  el: "#app",
  data: {
    test: "hello",
    options: [
    {
      value: "hello",
      text: "Hello"
    },
    {
      value: "solved",
      text: "Solved"
    }
    ]
  }
})
* {
  font-family: Arial;
}
<script src="https://ajax.googleapis./ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare./ajax/libs/select2/4.0.5/js/select2.min.js"></script>
<link href="https://cdnjs.cloudflare./ajax/libs/select2/4.0.5/css/select2.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare./ajax/libs/vue/2.5.17/vue.min.js"></script></script>

<div id="app">
  <bs-select v-model="test" :options="options"></bs-select>
  <br><br>
  {{ test }}
  
  <br><br>
  
  <button @click="test = 'solved'">
  Set 'test' variable to 'solved'
  </button>
</div>

It works quite nice, but he also suggested me to use this approach, which is a lot cleaner. I am currently using that now, but I leave the original answer to the question too, in case someone needs it.

I'm not sure what exactly you are trying to do here, but my guess is you were firing the onchange event twice, once when it actually changed and once in the watcher. Anyways you don't really need to use listeners like that when there are vue solutions available like this:

 <div id="app">
  <bs-select :value="test" v-on:change-value="test = $event" :options="options"></bs-select>
  <br><br>
  {{ test }}

  <br><br>

  <button @click="test = 'bug'">
  Set 'test' variable to 'bug'
  </button>
</div>

<div>
Event is firing twice in console...
</div>

ponent:

Vue.ponent("bs-select",{
template:
 `<select :value="value" v-on:change="changeVal" style="width: 100%">
    <option value="" selected disabled>Choose...</option>
    <option v-if="!options">{{ value }}</option>
    <option v-for="option in options" :value="option.value">{{ option.text }}</option>
  </select>`,
  props: ["value", "options"],
  methods: {
    changeVal: function(event) {
        this.$emit('change-value', event.target.value)
    }
  }
});

new Vue({
  el: "#app",
  data: {
    test: "bug",
    options: [
    {
      value: "hello",
      text: "Hello"
    },
    {
      value: "bug",
      text: "Bug"
    }
    ]
  }
})

https://jsfiddle/kv3bq1dw/

For anyone ing across this now, this is the proper way to get it to fire only once.

<template>
    <select><slot></slot></select>
</template>
<script>
  module.exports = {
    props: ['options', 'value'],
    mounted: function () {
        console.log(this.options);
        var vm = this;
        $(this.$el)
        // init select2
        .select2({
            data: this.options,
            theme: 'bootstrap',
            width: '100%',
            placeholder: 'Select',
            allowClear: true
        })
        .val(this.value)
        .trigger('change')
        // emit event on change.
        .on('select2:select', function () { // bind to `select2:select` event
            vm.$emit('input', this.value)
        });
    },
    watch: {
        value: function (value) {
            // update value
            $(this.$el)
            .val(value)
            .trigger('change');
        },
        options: function (options) {
            // update options
            $(this.$el).empty().select2({ data: options })
        }
    },
    destroyed: function () {
        $(this.$el).off().select2('destroy')
    }
  }
</script>

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745187965a4615727.html

相关推荐

  • javascript - Vue component $emit firing twice - Stack Overflow

    I'm recently trying to reutilize my Vue ponents in some real-world application to remove unnecessa

    12小时前
    30

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信