3

I am using Typescript Class component and I have this problem I can't use this.$refs.<refname>.focus()

Template Code:

 <header class="py-2 px-1 m-0 row">
    <input
      type="text"
      class="form-control m-1"
      ref="searchBoard"
      placeholder="Find boards by name..."
    />
  </header>

This input field is inside a popup.

Typescript Code:

import { Component, Vue } from "vue-property-decorator";

@Component
export default class BoardList extends Vue {

  // I added this to solve the compile error
  $refs!: {
    searchBoard: HTMLInputElement;
  };

  isShown = false;

  toggleDropdown() {
    this.isShown = !this.isShown;
    this.$refs.searchBoard.focus();
  }
} 

Then I get this Error:

enter image description here

this problem is fixed in this question Vuejs typescript this.$refs..value does not exist added:

  $refs!: {
    searchBoard: HTMLInputElement;
  };

I get a New Error in my console

[Vue warn]: Error in v-on handler: "TypeError: this.$refs.searchBoard is undefined"

found in

---> <BoardList> at src/components/boards/buttons/BoardList.vue
       <NavbarTop> at src/components/NavbarTop.vue
         <ComponentName> at src/App.vue
           <Root> vue.runtime.esm.js:619
    VueJS 

7

is there a way to do this?

5
  • The HTMLFormElement does not have a focus method. It should be typed as HTMLInputElement instead. Commented Feb 11, 2020 at 17:30
  • yes I updated it with HTMLInputElement, but I still get the error in console. > "TypeError: this.$refs.searchBoard is undefined" Commented Feb 11, 2020 at 17:33
  • Refs are non-reactive. Are you sure that the element is not conditionally rendered (e.g. found within an element with a v-if directive), and that it is definitely available when the method toggleDropdown is invoked? What happens if you log this.$refs to the console? Commented Feb 11, 2020 at 18:00
  • when I console its now showing the elements and its attributes. but the focus() is not working Commented Feb 11, 2020 at 18:30
  • its working now I added the .focus() inside a setTimeout(). it's wierd Commented Feb 11, 2020 at 18:35

3 Answers 3

8

Regarding the use of setTimeout:

Based on the timing of your code, it seems your isShown property controls whether or not the $refs.searchBoard is rendered in the DOM. Instead of setTimeout, Vue recommends using $nextTick to defer an action until the next DOM cycle:

toggleDropdown() {
  this.isShown = !this.isShown
  this.$nextTick(() => this.$refs.searchBoard.focus())
}

Regarding $refs:

A slightly cleaner alternative to the $refs type extension in your class is to use @Ref:

@Component
export default class BoardList extends Vue {
  @Ref() readonly searchBoard!: HTMLInputElement

  toggleDropdown() {
    this.isShown = !this.isShown
    this.$nextTick(() => this.searchBoard.focus())
  }
}
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you, this looks good but @Ref is giving VSCode error "'Ref' is not defined."
Import it beforehand: import { Ref } from 'vue-property-decorator'
1

I was able to make it work, I added .focus() inside setTimeout().

  toggleDropdown() {
    this.isShown = !this.isShown;

    setTimeout(() => {
      this.$refs.searchBoard.focus();
    }, 50);
  }

3 Comments

I've tried this and still returns error "Uncaught TypeError: _this2.$refs.specie.focus is not a function at eval"
This works for me in my inertia vue3 project. But it feels wrong. My console log in my onMount is undefined. Can anyone explain why we have to do a timeout?
@Nick The this.isShown if truthy will renders a new element on the DOM; we use setTimeout() to delay 'focus()' until the element has rendered on the DOM. I do advise using $nextTick() instead.
1

try this

toggleDropdown() {
    this.isShown = !this.isShown;
    this.$refs.searchBoard.$el.focus();
}

1 Comment

Please elaborate on the answer, so that OP understands WHY you think your solution is correct.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.