0

I can set focus to an input field, but not a select. What am I missing?

This works:

    <input matInput formControlName="name" required maxlength="100" id="elementFocus" appElementFocus="true" />

This does not

    <mat-select formControlName="countryId" required id="elementFocus" appElementFocus="true">

Here's the entire section that exists now, and when the page loads, the 2nd form element (Name) has focus. I need the select to have focus.

    <mat-card-content>

      <div fxLayout="column" fxLayoutGap="25px" class="container">

        
        <mat-form-field appearance="standard">
          <mat-label>Countries</mat-label>
          <mat-select formControlName="countryId" #countrySelectRef required>
            <mat-option *ngFor="let c of countries" [value]="c.id"
              >{{ c.name }}
            </mat-option>
          </mat-select>
          <mat-error *ngIf="hasError(f.countryId)">{{
            getErrorMessage(f.countryId)
          }}</mat-error>
        </mat-form-field>
        
        <mat-form-field appearance="standard">
          <mat-label>Name</mat-label>
          <input matInput formControlName="name" required maxlength="100" />
          <mat-hint align="end">{{ f.name.value.length }} / 100</mat-hint>
          <mat-error *ngIf="hasError(f.name)">{{
            getErrorMessage(f.name)
          }}</mat-error>
        </mat-form-field>
      </div>

    </mat-card-content>

.ts code (narrowed down to all that is relevant, I think).


  @ViewChild(MatSelect) countrySelectRef: MatSelect;

  constructor(
    private formBuilder: FormBuilder,
    private activatedRoute: ActivatedRoute,
    private router: Router,
    private matDialog: MatDialog,
    private readonly countryService: CountryService,
    private readonly stateService: StateService,
    private messageService: UIMessageService) { }

  ngOnInit(): void {
    const paramId = this.getParam('id');
    this.isAdd = !paramId
    this.id = !paramId ? uuid() : paramId
    this.heading = this.isAdd ? `Add ${this.headingName}` : `Edit ${this.headingName}`
    this.initForm();
    if (!this.isAdd) {
      this.patchForm()
    }
  }
  

  ngAfterViewInit(): void {

    if (this.countrySelectRef) {
      this.countrySelectRef.focus();
    }
  }
Matt Dawdy
  • 19,247
  • 18
  • 66
  • 91
  • 1
    Does this help https://stackoverflow.com/questions/54593925/how-to-set-auto-focus-in-mat-select? – Misha Mashina Feb 22 '22 at 21:26
  • Do you mean autofocus? Because from your code, it looks like it should focus the select, but since you are not using it inside a `mat-form-field` directive, the select is not being styled properly, hence, the focus style is not being applied. – David Fontes Feb 22 '22 at 21:32
  • I'm really trying here to make sense of what you are saying. I've relatively new to angular, and I cannot get me .ts backend file to actually figure out what #countryidForSelect is. I've given that mat-select the # directive: . But this line, that I just added to the .ts ngOnInit method, won't compile. if(this.countryidForSelect) this.countryidForSelect.focus(); – Matt Dawdy Feb 22 '22 at 21:50
  • @MishaMashina no that doesn't help, but that's likely because I don't understand the answer yet. Thank you for the pointer. – Matt Dawdy Feb 22 '22 at 21:57
  • Show us the TS code as well as the template. The `#countryIdForSelect` in the template is called a **template variable**, also called local reference, and while you can access them from the component (TS file), you need to perform an extra step, you need to use the decorator `ViewChild`. If you share your TS code we can show you. – David Fontes Feb 22 '22 at 22:25
  • @DavidFontes I just made sure that the .html and .ts sections are the ones you want to see. Thank you for being willing to help. – Matt Dawdy Feb 22 '22 at 22:42
  • Does this answer your question? [How to set auto focus in mat-select?](https://stackoverflow.com/questions/54593925/how-to-set-auto-focus-in-mat-select) – Chris W. Feb 22 '22 at 22:44
  • @ChrisW. no it doesn't. I'm trying to figure out why. But I'm getting this error when compiling: "Error: src/app/feature/states/states-edit/states-edit.component.ts:57:29 - error TS2339: Property 'focus' does not exist on type 'ElementRef'." – Matt Dawdy Feb 22 '22 at 22:55

1 Answers1

1

Your code has a problem, in the sense that it can trigger a ExpressionChangedAfterItHasBeenCheckedError error, but even with that error, it should work fine. Your code and the error message, described in your comment, don't match up and may indicate that the issue is elsewhere.

I do provide an alternative, which hopefully, will solve your problem. You need to add the A11yModule to the imports array of the module that declare the component that use that template.

Template

<mat-form-field appearance="standard" cdkMonitorSubtreeFocus>
    <mat-label>Countries</mat-label>
    <mat-select formControlName="countryId" #countrySelectRef required
    cdkTrapFocusAutoCapture
    cdkTrapFocus="false">
        <mat-option *ngFor="let c of countries" [value]="c.id">
            {{ c.name }}
        </mat-option>
    </mat-select>
    <mat-error *ngIf="hasError(f.countryId)">
        {{ getErrorMessage(f.countryId) }}
    </mat-error>
</mat-form-field>

Note the 2 (with 3 inputs in total) directives added:

  • cdkMonitorSubtreeFocus: considers an element focused if it or any of its children are focused
  • cdkTrapFocusAutoCapture: Whether the directive should automatically move focus into the trapped region upon initialization and return focus to the previous activeElement upon destruction.
  • cdkTrapFocus="false": If this value is true, it will trap the focus on that directive indefinitely.

Ref: Material documentation

David Fontes
  • 1,427
  • 2
  • 11
  • 16