Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to focus on an input in Angular

This should be simple but I can't find a solution, the closest answer i can find on SO is this: How do I programmatically set focus to dynamically created FormControl in Angular2

However this is way more convoluted that my requirements. Mine are simple. I have an input in the template like so:

<div *ngIf="someValue">    
    <input class="form-control" #swiper formControlName="swipe" placeholder="Swipe">
</div>

(Note, it's in an ngx-boostrap form-control group but I'm pretty sure this should not matter)

And I have a button that when clicked calls the following function:

onClick() {
    this.renderer.invokeElementMethod(this.swiper.nativeElement, 'focus')
}

The goal is that when the button is clicked, my input element gets focus. here is the rest of my component (the relevant parts):

import { Component, ElementRef, ViewChildren, Renderer } from '@angular/core';
import { MyService } from wherever/my/service/is

export class MyClass {
    @ViewChildren('swiper') input: ElementRef;
    someValue: any = false;

    constructor(private renderer: Renderer, service: MyService) {
       this.service.getSomeData().subscribe(data => {
          this.someValue = true;
       }
    }

    onClick() {
        this.renderer.invokeElementMethod(this.swiper.nativeElement, 'focus');
    }
}

The error I get is:

ERROR TypeError: Cannot read property 'focus' of undefined
at RendererAdapter.invokeElementMethod (core.js:12032)
etc...

Any ideas?

(Angular 5 btw)

Note, I edited the code to more accurately reflect what is actually going on, I think there may be some synchronization issue.

like image 573
Dallas Caley Avatar asked Apr 19 '18 18:04

Dallas Caley


3 Answers

You are using ViewChildren which returns a QueryList You need to use ViewChild and your code should work.

export class MyClass {
    @ViewChild('swiper') swiper: ElementRef;

    constructor(private renderer: Renderer) {}

    onClick() {
        this.swiper.nativeElement.focus();
    }
}
like image 56
Teddy Sterne Avatar answered Oct 06 '22 02:10

Teddy Sterne


Adding a cdkFocusInitial directive works for me:

<input
    matInput
    cdkFocusInitial />
like image 23
sai amar Avatar answered Oct 06 '22 02:10

sai amar


This is how I solved it:

Template:

<input class="form-control" #swiper formControlName="swipe" placeholder="Swipe">

Component:

import { Component, ElementRef, ViewChild } from '@angular/core';

export class MyClass {
    @ViewChild('swiper') swiper: ElementRef;

    constructor() {}

    onClick() {
        this.swiper.nativeElement.focus();
    }
}

The key being two things: first using the ViewChild not ViewChildren (thanks @Teddy Stern for that one) and second there is no need to use the Renderer at all, just directly use the nativeElement's focus function.

like image 28
Dallas Caley Avatar answered Oct 06 '22 02:10

Dallas Caley