Vuesax: .focus() on vs-input inside vs-popup not working

Created on 9 Jan 2019  路  10Comments  路  Source: lusaxweb/vuesax

Having this template code:

<vs-popup classContent="popup-example" title="Tarea" :active.sync="popupIsActive">
  <vs-input id="taskDescription" class="inputx" placeholder="Descripci贸n de la tarea" v-model="taskDescription"/>
  <br>
   <vs-button
          id="setFocusButton"
          @click="setFocusOnInput()"
          color="primary"
          type="filled"
   >Set Focus on Input</vs-button>
</vs-popup>

I would like to set the focus on the vs-input control, each time the popup is loaded.

For that I have this watch:

  watch: {
    popupIsActive() {
      if (this.popupIsActive) {
        console.log(document.getElementById('taskDescription'));    // <==  the input exists in DOM
        document.getElementById('taskDescription').focus();         // <== but the focus is not set
      }
    },
  },

But the focus is not set.

Otherwise, if I click on the button, the focus is set:

 methods: {
    setFocusOnInput() {
      console.log(document.getElementById('taskDescription'));    // <==  the input exists in DOM
      document.getElementById('taskDescription').focus();         //  <== this time the focus is set
   },
},

I presume it has something to do with the hooks of vs-popup component, but I'm not really sure.

If anyone could point me at the right direction I would really appreciate it.

Thanks!

Most helpful comment

Please, try this code bellow, it does the job with a different approach but the result is the same. I reccomend you to avoid use document whenever possible. It's preferiable to set a reference in your element/componet witch is provided natively by Vue.js API. It works properly even with SSR and also prevent side effects outside your component instance, for example.
I believe the issue is that you are tryng to focus the root element of vs-input, and it's probably not a native input. Another thing to consider is when the popup is shown it's possible that the target input is not avaliable immediately.

ps: I didn't try to run this code myself so let me know if it works. ;)

 <vs-input 
     ref="taskDescription"
     class="inputx" 
     placeholder="Descripci贸n de la tarea" 
     v-model="taskDescription"
 />
 <br>
 <vs-button
     id="setFocusButton"
     @click="setFocusOnInput('taskDescription')"
 >Set Focus on Input</vs-button>

I belive you forgot the $nextTick trick inside the watcher...

popupIsActive() {
    if (this.popupIsActive) {
        this.$nextTick(() => this.setFocusOnInput('taskDescription'))
   }
}

Now, you have a generic and reusable setFocus method:

setFocusOnInput(inputName) {
   /** 
    * @see https://vuejs.org/v2/api/#vm-el 
    * @see https://vuejs.org/v2/api/#vm-refs
    */
    // you could just call this.$refs[inputName].focusInput() but i'm not shure if it belongs to the public API
    let inputEl = this.$refs[inputName].$el.querySelector('input') <== Now you have an input 
    console.log(inputEl.focus) // <== See if `focus` method avaliable
    inputEl.focus() //  <== This time the focus will work properly
}

All 10 comments

Please, try this code bellow, it does the job with a different approach but the result is the same. I reccomend you to avoid use document whenever possible. It's preferiable to set a reference in your element/componet witch is provided natively by Vue.js API. It works properly even with SSR and also prevent side effects outside your component instance, for example.
I believe the issue is that you are tryng to focus the root element of vs-input, and it's probably not a native input. Another thing to consider is when the popup is shown it's possible that the target input is not avaliable immediately.

ps: I didn't try to run this code myself so let me know if it works. ;)

 <vs-input 
     ref="taskDescription"
     class="inputx" 
     placeholder="Descripci贸n de la tarea" 
     v-model="taskDescription"
 />
 <br>
 <vs-button
     id="setFocusButton"
     @click="setFocusOnInput('taskDescription')"
 >Set Focus on Input</vs-button>

I belive you forgot the $nextTick trick inside the watcher...

popupIsActive() {
    if (this.popupIsActive) {
        this.$nextTick(() => this.setFocusOnInput('taskDescription'))
   }
}

Now, you have a generic and reusable setFocus method:

setFocusOnInput(inputName) {
   /** 
    * @see https://vuejs.org/v2/api/#vm-el 
    * @see https://vuejs.org/v2/api/#vm-refs
    */
    // you could just call this.$refs[inputName].focusInput() but i'm not shure if it belongs to the public API
    let inputEl = this.$refs[inputName].$el.querySelector('input') <== Now you have an input 
    console.log(inputEl.focus) // <== See if `focus` method avaliable
    inputEl.focus() //  <== This time the focus will work properly
}

Thank you @JimmyBastos. I'll try it and I'll let you know.

@ccalvarez Tell me, did you manage to solve it? is to review or close the prolema, thank you very much for the contribution

Thank You @JimmyBastos . I also have this problem right now. @luisDanielRoviraContreras I'm waiting for update. My project is in ending stage. Please merge it.

@JimmyBastos:

ps: I didn't try to run this code myself so let me know if it works. ;)

the approach you suggested with setFocusOnInput method works perfect, the input receives the focus each time the popup is activated: video here

The other approach with just commit https://github.com/JimmyBastos/vuesax/commit/637baa8ea3702eb044b986807f6217e4edd2dc91 (without the watch + setFocusOnInput method), works fine but only when the popup is activated for the first time. The following times that the popup is activated, the input doesn't receive the focus anymore: video here. It is understood, because of the nature of the autofocus attribute of input.

@ccalvarez It's my pleasure to help! I didn't know it's a known "issue" of HTML. I'll try to manage that as soon as possible, thanks for your report!

Thank you very much @JimmyBastos. Well I didn't mean that it's an "issue", I meant rather that the documentation indicates that autofocus sets the focus when the page has finished loading, which I think in this case occurs once :)

@ccalvarez I got your point, but i didn't choose the appropriate words.

The problem was solved, many thanks to all for the contribution

Here is my working solution

<vs-input 
     ref="email"
     placeholder="Descripci贸n de la tarea" 
     v-model="taskDescription"
 >
</vs-input>

here is my method

var input = this.$refs.**email**.$el.querySelector("input");
input.focus();

Was this page helpful?
0 / 5 - 0 ratings