I have a select ponent. I have a input ponent. When the select ponent is changed I need to .select() the input ponent. These are two unrelated ponents i.e. siblings to the main Vue instance.
Both of these ponents are posed from templates so using the ref attribute is not an option as per the documentation .html#Child-Component-Refs
How would I go about doing this? I've posed a simple example in codepen -
HTML
<div id='my-app'>
<some-select></some-select>
<some-input></some-input>
</div>
<script type="text/x-template" id="vueTemplate-some-select">
<select @change="doStuff">
<option value='1'>Value 1</option>
<option value='2'>Value 2</option>
</select>
</script>
<script type="text/x-template" id="vueTemplate-some-input">
<input ref='text-some-input' type='text' value='Some Value'/>
</script>
Vue Code
Vueponent('some-input', {
template: `#vueTemplate-some-input`
});
Vueponent('some-select', {
methods: {
doStuff: function() {
// Do some stuff
//TODO: Now focus on input text field
//this.$refs['text-some-input'].focus(); // Cant use refs, refs is empty
}
},
template: `#vueTemplate-some-select`
});
var app = new Vue({
el: '#my-app'
});
I have a select ponent. I have a input ponent. When the select ponent is changed I need to .select() the input ponent. These are two unrelated ponents i.e. siblings to the main Vue instance.
Both of these ponents are posed from templates so using the ref attribute is not an option as per the documentation https://v2.vuejs/v2/guide/ponents.html#Child-Component-Refs
How would I go about doing this? I've posed a simple example in codepen - https://codepen.io/anon/pen/MVmLVZ
HTML
<div id='my-app'>
<some-select></some-select>
<some-input></some-input>
</div>
<script type="text/x-template" id="vueTemplate-some-select">
<select @change="doStuff">
<option value='1'>Value 1</option>
<option value='2'>Value 2</option>
</select>
</script>
<script type="text/x-template" id="vueTemplate-some-input">
<input ref='text-some-input' type='text' value='Some Value'/>
</script>
Vue Code
Vue.ponent('some-input', {
template: `#vueTemplate-some-input`
});
Vue.ponent('some-select', {
methods: {
doStuff: function() {
// Do some stuff
//TODO: Now focus on input text field
//this.$refs['text-some-input'].focus(); // Cant use refs, refs is empty
}
},
template: `#vueTemplate-some-select`
});
var app = new Vue({
el: '#my-app'
});
Share
edited Jul 14, 2022 at 1:18
tony19
139k23 gold badges278 silver badges348 bronze badges
asked Mar 22, 2018 at 12:36
Andrew BerridgeAndrew Berridge
4936 silver badges16 bronze badges
1
- Here is one way. codepen.io/Kradek/pen/yKbwVB?editors=1010 – Bert Commented Mar 22, 2018 at 12:40
2 Answers
Reset to default 2There are several ways you could do this, and the right one depends on what the reasons are for implementing this behavior. It sounds like the value selected is significant to the app, rather than just being relevant to the select ponent, so it should e from the parent. The parent can also pass that value to the input, which can watch
it for changes and set focus.
That solution might look like this snippet:
Vue.ponent("some-input", {
template: `#vueTemplate-some-input`,
props: ['watchValue'],
watch: {
watchValue() {
this.$refs['text-some-input'].focus();
}
}
});
Vue.ponent("some-select", {
props: ['value'],
methods: {
doStuff: function(event) {
this.$emit('input', event.target.value);
}
},
template: `#vueTemplate-some-select`
});
var app = new Vue({
el: "#my-app",
data: {
selectedValue: null
}
});
<script src="//unpkg./vue@latest/dist/vue.js"></script>
<div id='my-app'>
<some-select v-model="selectedValue"></some-select>
<some-input :watch-value="selectedValue"></some-input>
<div>Selected: {{selectedValue}}</div>
</div>
<script type="text/x-template" id="vueTemplate-some-select">
<select :value="value" @change="doStuff">
<option value='1'>Value 1</option>
<option value='2'>Value 2</option>
</select>
</script>
<script type="text/x-template" id="vueTemplate-some-input">
<input ref='text-some-input' type='text' value='Some Value' />
</script>
If, on the other hand, you really want to know that the select
changed, and not just that the value changed, you could pass an event bus to the input so that the parent could relay the change to its child. That might look like this snippet:
Vue.ponent("some-input", {
template: `#vueTemplate-some-input`,
props: ['changeBus'],
mounted() {
this.changeBus.$on('change', () => this.$refs['text-some-input'].focus());
}
});
Vue.ponent("some-select", {
methods: {
doStuff: function(event) {
this.$emit('change', event.target.value);
}
},
template: `#vueTemplate-some-select`
});
var app = new Vue({
el: "#my-app",
data: {
changeBus: new Vue()
}
});
<script src="//unpkg./vue@latest/dist/vue.js"></script>
<div id='my-app'>
<some-select @change="changeBus.$emit('change')"></some-select>
<some-input :change-bus="changeBus"></some-input>
</div>
<script type="text/x-template" id="vueTemplate-some-select">
<select @change="doStuff">
<option value='1'>Value 1</option>
<option value='2'>Value 2</option>
</select>
</script>
<script type="text/x-template" id="vueTemplate-some-input">
<input ref='text-some-input' type='text' value='Some Value' />
</script>
This keeps things encapsulated: the parent knows only that one child changes and that the other child handles change events. Neither ponent knows about the other.
You need to emit a custom event from you select-ponent to the parent : VueJS Custom Events
Parent ponent :
<select-ponent @valueChanged="this.$refs.myInput.focus()"></select-ponent>
<input type="text" ref="myInput"/>
Select Component :
<select v-model="mySelectValue" @change="$emit('valueChanged', mySelectValue)"></select>