Reputation: 8081
I have the a component, with a template like this:
<template>
<div class="referenceparent">
<input
v-model="searchterm"
type="text"
@input="Search"
>
<ul
>
<li
v-for="(res, index) in searcheventresults"
:key="index"
>
{{ res }}
</li>
</ul>
</div>
</template>
I have a parent using this component like this:
<div class="col-sm-1">
<input
id="el1"
:ref="'DurnRef' + index"
v-model="editedPrescription[index].durn"
type="text"
class="form-control Durn input-sm"
placeholder="5"
aria-label="Durn"
@keyup.enter="DurnSelected(index)"
>
</div>
<div class="col-sm-2">
<autocomplete-input
:ref="'DurnUnitRef' + index"
placeholder="days"
arialabel="DurationUnits"
:searcheventresults="freqresults[index]"
:defaultterm="editedPrescription[index].freq"
@changed="(term) => {FreqSearch(term, index)}"
@selected="(term) => {FreqSelected(term, index)}"
/>
What I want to do, it, when I press Enter key on el1, I need to programmatically move focus to the input element in autocomplete-input. I tried adding a ref to autocomplete-input like above, hoping that the reference would propogate to the child input element. But when I called the ref with:
this.$refs[`DurnUnitRef${index}`].focus();
But that does not work. When I checked that object, I found that it does not have a focus method. How can I achieve what I want, i.e focus on a particular element which is a child element of a component, programmatically from the parent in which the component is embedded?
Upvotes: 1
Views: 6036
Reputation: 8081
A possible solution:
Aim: An event in an input element needs to set focus on an element, which is a child of a sibling of the input element which triggers the event.
#Parent Element
<div class="col-sm-1">
<input
:ref="'DurnRef' + index"
type="text"
@keyup.enter="FocusDurnUnit(index)"
>
</div>
<div class="col-sm-2">
<autocomplete-input
:ref="'DurnUnitRef' + index"
:ref-str="'DurnUnitRef' + index"
/>
</div>
In the above, @keyup.enter
on the input tag needs to set focus on a child of the autocomplete-input component. To do that, I first set a ref to the autocomplete-input component, and also pass a prop which holds the name of the same ref string.
In the autocomplete-input component, I get the prop refStr
, and assign the same as the ref to the input element which is nested inside autocomplete-input component like this:
#AutocompleteInput.vue
<template>
<div
class="referenceparent"
tabindex="0"
>
<input
:ref="refStr"
type="text"
>
</div>
</template>
Then, back in the parent component, in the method FocusDurnUnit(index) which handles the event which needs to triger focusing, I refer to the element of the child (nested component), by the following code:
FocusDurnUnit(index) {
let myref = this.$refs[`DurnUnitRef${index}`].$refs[`DurnUnitRef${index}`]
myref.focus()
},
So the key takehome message is that one can get the ref of a nested child by referring to the ref of the parent, and set one for the parent component if it exists.
Here, this.$refs[DurnUnitRef${index}]
is the ref of the autocomplete-input
element, and .$refs[DurnUnitRef${index}
refers to the ref of the child input element in autocomplete-input
This solved my issue and works well. If there's an easier or simpler solution, kindly share it.
Upvotes: 0
Reputation: 2856
Is hard to get which problem you're experiencing without a working fiddle, but I noticed two things that can be, or contribute to causing the behaviour.
You are asking to focus the ref attached to the component but your inner component with the input is wrapped inside a div
. Doing so, the focus will be called on that div
element, and that element does not have a tabindex
property set, and divs are not focusable by default.
Another problem cause, is that you are not waiting for nextTick, though it could also be happening that the focus is being set before the DOM content is updated.
I put a fiddle here that explains both concepts. Let me know if this helped
var myApp = new Vue({
el: '#app',
data() {
return {
focus: false
}
},
methods: {
switchAndFocus() {
this.$nextTick(function(){
this.$refs.toFocus.focus();
this.focus = true;
});
},
},
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.3/vue.min.js"></script>
<style>
.container {
padding: 10px;
}
.testing {
border: solid lightgray 1px;
}
.testing:focus {
border: solid red 1px;
}
</style>
<div id="app" class="container">
<div >
<button @click="switchAndFocus">Click to focus</button>
<h class="testing" ref="toFocus" tabindex="1">Is {{!focus ? '' : 'focused'}}
</div>
</div>
Upvotes: 1