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