Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to set autofocus on a matInput element on click event in Angular 6?

Similar to Google Login page, I want to have autofocus on input element after on click event. I have tried @ViewChild('id') and document.getElementId('id'). Both of it doesn't work. It's always null or undefined. How can I achieve this?

       <mat-form-field class="example-full-width col-sm-4">
        <input autofocus id="login-username" matInput 
       formControlName="userName" minlength="5" maxlength="20" 
       name="userName" placeholder="Username" required #input> 
      </mat-form-field>

        <div class="col-sm-12">
           <button (click)="changeView()" type="button" mat-raised-
             button color="primary">Next</button>
          </div>

         <mat-form-field class="example-full-width col-sm-4" 
          #passwordInput>
        <input autofocus type="password" matInput 
       placeholder="Password" minlength="5" maxlength="20" 
       formControlName="userPassword" #passwordInput>  
      </mat-form-field>
like image 869
Srihari GouthamGr Avatar asked Jul 25 '18 04:07

Srihari GouthamGr


People also ask

What is MatFormFieldControl?

MatFormFieldControl. An interface which allows a control to work inside of a MatFormField .

How do I change the color of my mat form field?

To change the mat form field border color in Angular, you have to target the . mat-form-field-outline class . This class is responsible for the 4 sides of borders around the mat form field element. So, to change the mat form field border color, you have to simply override the existing border color with the new one.


2 Answers

Unfortunately not every solution consistently works with autofocusing matInput at the moment of rendering. Here is what I tried:

  • HTML autofocus attribute
  • JS input.focus()
  • cdkFocusInitial from @angular/cdk

All of the above methods might work but under some conditions they appear to be broken.

What consistently and always works is using a high-level api of the matInput. Here is a simple directive that uses this approach:

import { Directive, OnInit } from '@angular/core';
import { MatInput } from '@angular/material/input';

@Directive({
  selector: '[matInputAutofocus]',
})
export class AutofocusDirective implements OnInit {

  constructor(private matInput: MatInput) { }

  ngOnInit() {
    setTimeout(() => this.matInput.focus());
  }

}

The timeout is required to delay focusing the element because matInput does not properly function at the moment of creating yet. Usage:

<mat-form-field>
  <input type="text" matInput matInputAutofocus>
</mat-form-field>

Of course, naming the selector matInputAutofocus is dangerous because material itself can come to this solution one day. Use it on your own risk or just rename with your prefix (recommended).

Focus and meanwhile select the input value

A cherry on the cake is adding the possibility to also preselect the content of the input (this is most of the time more user-friendly), which slightly changes the implementation:

import { Directive, OnInit } from '@angular/core';
import { MatInput } from '@angular/material/input';
    
@Directive({
  selector: '[matInputAutofocus]',
})
export class AutofocusDirective implements OnInit {

  @Input()
  autofocusSelectValue = false;

  constructor(
    private matInput: MatInput,
    private elRef: ElementRef<HTMLInputElement>,
  ) { }

  ngOnInit(): void {
    setTimeout(() => {
      this.matInput.focus();

      if (this.autofocusSelectValue) {
        this.elRef.nativeElement.setSelectionRange(0, input.value.length);
      }
    });
  }

}

Use it as:

<mat-form-field>
  <input type="text" matInput matInputAutofocus [autofocusSelectValue]="true">
</mat-form-field>
like image 159
smnbbrv Avatar answered Oct 03 '22 04:10

smnbbrv


If you want to set focus to an Input field as soon as the page loads, you can do it simply by applying HTML attribute to that element, such as :

<input type="text" #input1 autofocus>

Else if you want to do this from your component.ts conditionally, use:

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

 @ViewChild('input1') inputEl:ElementRef;

 ngAfterViewInit() {
 this.inputEl.nativeElement.focus();
 }

Or you can use:

First import the renderer2 from @angular/core and then,

    const element = this.renderer.selectRootElement('#input1');

 setTimeout(() => element.focus(), 0);

Whatever you seems to be comfortable with your existing code.

like image 29
Saket Avatar answered Oct 03 '22 03:10

Saket