Angular 2 Material input focus not working

2020-03-11 04:29发布

问题:

The inputs are inside of a modal dialog. I have no idea why it is not working. I looked at the official docs and it listed focus as something you can pass to the element but it's not working?

Does anyone know why?

Angular Material - Input Docs

<form class="example-form">

  <md-input-container class="example-full-width" style="width: 300px; padding: 5px; border-radius: 10px;">
    <input mdInput type="email" name="to" placeholder="Email">
    <md-error></md-error>
  </md-input-container>

  <md-input-container focus focused>
    <input mdInput type="text" name="a" placeholder="zzzz" focus focused (focus)="">
  </md-input-container>

</form>

回答1:

Your attempts do not work because:

  • focused is a property driving the mat-focused class on mdInputContainer. You can use it to know whether your input is focused or not. You cannot use it to change the focus state.
  • focus is a method on mdInput that lets you programmatically focus the input. You can call the myInput.focus() with myInput being something like ViewChild('myInput') for instance.

But the simplest way to achieve what you want is to use the standard autofocus attribute :

<md-input-container>
    <input mdInput type="text" name="a" placeholder="zzzz" autofocus>
</md-input-container>


回答2:

Have you try with cdkFocusInitial which will specify the element that will receive focus upon initialization

documentation can be found here



回答3:

<form class="example-form">
  <md-input-container class="example-full-width" style="width: 300px; padding: 5px; border-radius: 10px;">
    <input mdInput #emailInput="matInput" type="email" name="to" placeholder="Email">
    <md-error></md-error>
  </md-input-container>
</form>

Then in the controller:

@ViewChild('emailInput') searchInput: MatInput;
....
ngAfterViewInit() {
  this.emailInput.focus();
}

What this.emailInput.focus() does is actually "elementRef.nativeElement.focus()" https://github.com/angular/material2/blob/master/src/lib/input/input.ts#L287

so you could do that your self like:

this.emailInput.nativeElement.focus()


回答4:

I was struggling with the same issue. I was using F6 to open the dialog and I could not get the <input> to get focus. It turned out that I wasn't preventing the default behavior of F6 and F6 highlights the browser URL window; so it was stealing focus.

switch (event.keyCode) {
      case 117:
        event.preventDefault();
        this.openAddAveragesDialog();
        break;
      default:
        return;
    }

Also, no magic tag attribute works. Autofocus, Focused, Focus, whatever, no dice. I had to create a directive and use that in my input element. I got help with that using this answer.

Here is the element after adding the directive (numberOnly is another directive for only number input):

<md-input-container> <input mdInput [focus]="true" [numberOnly]="true"/></md-input-container>

**Edit : Adding Directive code as suggested by @Mackelito for clarity. Here is the directive I wrote using the answer I linked above. Keep in mind material has changed their tag labels to <input matInput> from <input md-input>

import {Directive, ElementRef, Inject, Input, OnChanges, OnInit,     Renderer} from '@angular/core';

@Directive({
  selector: '[focus]'
})

export class FocusDirective implements OnChanges, OnInit {
@Input()
focus: boolean;

constructor(@Inject(ElementRef) private element: ElementRef, public renderer: Renderer) {}

ngOnInit() {
    this.renderer.invokeElementMethod(this.element.nativeElement,   'focus', []);
}

public ngOnChanges() {
this.element.nativeElement.focus();
}

} 


回答5:

You can usually set focus without any Typescript code, using the Template markup. But in the case of a Dialog, you'll need to use @Mackelito's solution with @ViewChild and ngAfterViewInit().

I had to focus a TextArea that's inside a Menu, when that Menu appears. Fortunately, Menu has a (menuOpened) event I could bind to.

  <button mat-stroked-button color="accent" [matMenuTriggerFor]="addMenu"
    (menuOpened)="newTypes.focus()">
    Add
    <mat-icon class="dyna-dropdown-arrow">arrow_drop_down</mat-icon>
  </button>
  <mat-menu #addMenu="matMenu" [overlapTrigger]="false">
    <form [formGroup]="formGroup" (ngSubmit)="onFormSubmit()" novalidate (keydown.tab)="$event.stopPropagation()">
      <mat-form-field appearance="outline" (click)="$event.stopPropagation(); false;">
        <mat-label>New Pay Types</mat-label>
        <textarea #newTypes rows="6" matInput placeholder="New Pay Types" [formControl]="formGroup.controls['payTypes']" required></textarea>
        <mat-hint>Enter multiple Pay Types, separated by newlines</mat-hint>
        <mat-error *ngIf="formGroup.controls['payTypes'].invalid">Required</mat-error>
      </mat-form-field>
      <div fxLayout="row-reverse" fxLayoutGap="8px" fxLayoutAlign="start center">
        <button mat-stroked-button color="accent" type="submit" [disabled]="!formGroup.valid">Add</button>
        <button mat-button type="button">
          Cancel
        </button>
      </div>
    </form>
  </mat-menu>

The important part here is the (menuOpened)="newTypes.focus()" and we see the newTypes is a TemplateRef variable attached to the TextArea I want to focus marked as <textarea #newTypes.

Here's a screen shot that shows my menu opening up and it immediately gets focus to the Textarea inside it.



回答6:

Try to add some delay before set the input get focus. I've made this behavior a directive for your reference.

delay-focus.ts

import { Directive, Input, ElementRef } from '@angular/core';

@Directive({
  selector: '[delayFocus]'
})
export class DelayFocusDirective {

  @Input() delayFocusInterval;
  @Input() set delayFocus(condition: boolean) {
    if (condition) {
      console.log(this.delayFocusInterval);
      setTimeout(() => {
        this.el.nativeElement.focus();
      }, this.delayFocusInterval | 500);
    }
  }
  constructor(private el: ElementRef) { }
}

example

<input type="text" placeholder="Delay 100ms to get focus" delayFocus="true" delayFocusInterval="100">

You can try it here.