I have web app where interface is based on vue.js 2.0.
I have component which displays input based on select2 plugin.
By default it shows selected options, but when user clicks on it, I show select2 to allow user modify options.
Code looks like this:
<template>
<div @click="toggleEdit">
    <span v-show="isEnabled">
        <select
            class="form-control"
            :name="name"
            :multiple="multiple"
        >
            <option v-for="opt in options" :value="opt.id"> {{ opt.text }} </option>
        </select>
    </span>
    <span v-show="!isEnabled">
        <div v-if="selectedOptions.length === 0">
            {{ emptyText }}
        </div>
        <div v-for="opt in selectedOptions">
            {{ opt }}
        </div>
    </span>
</div>
</template>
<script>
export default {
    props: {
        options: {
            type: Array,
            required: false,
            default: function() {
                return []
            }
        },
        name: {
            required: true,
            type: String
        },
        multiple: {
            required: false,
            type: Boolean,
            default: false
        },
        emptyText: {
            required: false,
            type: String,
            default: ""
        },
        sourceUrl: {
            required: false,
            type: String,
            default: ""
        },
        enabled: {
            required: false,
            type: Boolean,
            default: false
        }
    },
    data() {
        return {
            isEnabled: this.enabled
        }
    },
    watch: {
        options: {
            handler: function() {
                console.log(arguments)
            },
            deep: true
        }
    },
    mounted: function() {
        this.select = $(this.$el).find("select");
        this.select.select2();
        var that = this;
        this.select.on("change", function(e) {
            var indexMap = {};
            for(var i = 0; i < that.options.length; i++) {
                that.options[i].selected = false;
                indexMap[that.options[i].id] = i;
            }
            var selected = that.select.select2('val');
            if(typeof selected === "string") {
                selected = [selected];
            }
            for(var i = 0; i < selected.length; i++) {
                var index = indexMap[selected[i]];
                console.log(index)
                console.log(selected[i])
                if(index !== undefined) {
                    var option = that.options[index];
                    option.selected = true;
                    that.$set(that.options, index, option);
                }
            }
        })
        this.select.on("select2:open", function() {
            that.isEnabled = true;
        });
        this.select.on("select2:close", function() {
            that.isEnabled = false;
        });
    },
    methods: {
        toggleEdit() {
            if(this.isEnabled) return; // to pass select2 clicks
            this.isEnabled = !this.isEnabled;
            var that = this;
            this.$nextTick(function() {
                that.select.select2("open");
            });
        }
    },
    computed: {
        selectedOptions: function() {
            console.log(this.options)
            return this.options.filter(function(option) {
                console.log(option.selected);
                if(option.selected === true) return true;
                return false;
            });
        }
    }
}
The problem is: I want to show multiple different selects using this component. Name attribute can be one of the following: model1[field1], model1[field2], ..., model40[field1], ..., model99[field15], where every modelN corresponds to tables in databases with it's respective fields.
When user changes options, ajax request must be sent to server, which returns json-object like this
{
   "errorText": null or "text with error",
   "disableFields": ["model3[field4]", "model24[field15]"]
}
I want to parse "disableFields" array and to disable from this component  another component.
One way to accomplish this (pseudo code):
foreach field in disableField:
    $(document).trigger("disableField" + field);
And in mounted method of this component
var self = this;
$(document).on("disableField" + this.name, function() {
    self.isEnabled = false
})
Is there a better way to do this without parent component?
The best way to force Vue to re-render a component is to set a :key on the component. When you need the component to be re-rendered, you just change the value of the key and Vue will re-render the component.
You can use this.$root without global variable:
// component A emits an event
export default {
  name: 'A',
  methods: {
    buttonClicked: function () {
      this.$root.$emit('myEvent', 'new message!');
    }
  }
// component B catch your event
export default {
  name: 'B',
  data () {
    return {
        message: 'Old message!'
    }
  },
  mounted: function () { 
    this.$root.$on('myEvent', (text) => { // here you need to use the arrow function
     this.message = text;
    })
  }
}
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With