vuejs: Trying to focus the input using v-el directive

31.9k Views Asked by At

I am creating a wizard login form where the Mobile Number is first entered and password is entered next.

Here am trying to focus the password input using

this.$$.passwordInput.focus()

however if am getting the error given below

Uncaught TypeError: Cannot read property 'focus' of undefined

The full code is below

index.html

<div id="login">
  <div v-if="flow.mobile">
    <form v-on="submit: checkmobile">
        <p>
          Mobile Number<br>
          <input type="text" v-model="mobile_number" v-el="mobileNumber">
        </p>
    </form>
  </div>
  <div v-if="flow.password">
    <form v-on="submit: checkpassword">
        <p>
          Password<br>
          <input type="password" v-model="password" v-el="passwordInput">
        </p>
    </form>
  </div>

script.js

var demo = new Vue({
el: '#login',
data: {
    flow: {
        mobile: true,
        password: false
    }
},
methods: {
    checkmobile: function(e) {
        e.preventDefault();
        this.flow.mobile = false;
        this.flow.password = true;
        this.$$.passwordInput.focus();
    },
    checkpassword: function(e) {
        e.preventDefault();
    }
}

});

7

There are 7 best solutions below

1
On BEST ANSWER

Your passwordInput is inside a v-if block, which only gets rendered when you set flow.password to true; However Vue uses asynchronous rendering, so the v-if block will not be rendered immediately. You can use Vue.nextTick to wait until it does:

this.flow.password = true;
var self = this;
Vue.nextTick(function () {
  self.$$.passwordInput.focus();
});

Read the guide about async rendering for more details.

0
On

Vue.js 1 works a bit different.

Example:

  <textarea v-el:model_message></textarea>

JS:

this.$els.model_message.focus();
0
On

Vue v2's documentation uses focus as an example in writing custom directives. All of the needed code is supplied with the example, https://v2.vuejs.org/v2/guide/custom-directive.html. First you must register the directive. The link shows how to register it locally on the component.

// Register a global custom directive called `v-focus`
Vue.directive('focus', {
  // When the bound element is inserted into the DOM...
  inserted: function (el) {
    // Focus the element
    el.focus()
  }
})

Having done this, you are now able to use v-focus on an element:

<input v-focus>

Like so.

1
On

If you are using vuejs 2, you should read this:

https://v2.vuejs.org/v2/guide/migration.html#v-el-and-v-ref-replaced

--

In this case, in your template:

use ref="passwordInput" instead v-el="passwordInput"

and in your method:

this.$refs.passwordInput.focus()

I hope this help you!

0
On

Glad this worked for some of you. I have no idea why, but after trying every conceivable variation of the accepted answer I could not get the $$.ref property when using v-repeat. I could only access the newly created dom elements like so:

new Vue({
el: '#reporting_create',
data: {
    recipients: {
        0: {
            fname: null,
            lname: null,
            email: null,
            registration: false,
            report: false
        }
    },
    curRec:1
},
methods: {
    addRecipient: function(){
        event.preventDefault();
        this.recipients.$add(
            this.curRec,
            {
                fname: null,
                lname: null,
                email: null,
                registration: false,
                report: false
            }
        );
        var num = this.curRec;
        this.$nextTick(function () {
            console.log(this._children[num].$$.rowrec);
            newSwitches.find('.switch').bootstrapSwitch();
        })

        this.curRec++;
    }
}})

html:

<template v-repeat="recipients">
        <div class="row" v-el="rowrec">
            <div>{{$key}}</div>
        </div>
</template>

The addRecipients function was called outside the v-repeat so even the suggested answer here did couldn't help

Not sure if there is an issue with doing it this way but it works and I'm tired.

1
On

If you are using Vue.js 2.0, you should do the following:

<input type="text" v-model="currentItem.name" ref="txtName">

So you can access this input by using the $refs object:

this.$refs.txtName.focus();

I hope it helps.

4
On

In Vue.js 2.x you can create your own directive to focus a field automatically:

Vue.directive('focus', {
    inserted: function (el) {
        el.focus();
    },
    update: function (el) {
        Vue.nextTick(function() {
              el.focus();
        })
    }
})

Then you can use v-focus attribute on inputs and other elements:

<input v-focus>

Working example: https://jsfiddle.net/LukaszWiktor/cap43pdn/