0

*There are a lot of similar questions but I have not found a true duplicate that answers my question Apologies if I missed something.

I have a page with several inputs/buttons (The same component repeated) and need to focus on the correct input upon button click.

I have tried variations of elementRef, nativeElement, focusing based on the ID... but I can only get it to focus on the first one in the DOM or specific ones...

<ng-template #myTemplate let-context="context">
<input #foo [id]="'myInput'+context.id" />
<button class="btn" [id]="'btnAction'+context.id (click)="focusOnInput()"></button>
</ng-template>

Which renders like this in the DOM:

<input #foo id="myInput1" />
<button class="btn" id="btnAction1></button>

<input #foo id="myInput2" />
<button class="btn" id="btnAction2></button>

<input #foo id="myInput3" />
<button class="btn" id="btnAction3></button>

This is what I've been trying:

@ViewChild("foo") focusOnThis: ElementRef;
focusOnInput(): void {
this.focusOnThis.nativeElement.focus();
}

Desired behavior: When clicking on the button, focus on the respective input. Currently, it only focuses on the first one, or whichever ID I specify...

user3390251
  • 317
  • 2
  • 5
  • 22

2 Answers2

2

You can call foo.focus() in the button click handler. Since the scope of the template reference variable #foo is the template instance, it will refer to the sibling input element.

<ng-template #myTemplate let-context="context">
  <input #foo />
  <button class="btn" (click)="foo.focus()"></button>
</ng-template>

See this stackblitz for a demo.


If you need to set the focus from a method, pass foo to it as an argument:

<ng-template #myTemplate let-context="context">
  <input #foo />
  <button class="btn" (click)="focusOnInput(foo)"></button>
</ng-template>
focusOnInput(input): void {
  // Do something else here
  ...
  input.focus();
}
ConnorsFan
  • 70,558
  • 13
  • 122
  • 146
  • appreciate the response. this seems clean and simple but unfortunately its not working in my project. there are other events that need to fire first to make the input visible, so I'm guessing that's causing issues. Preferably I would set the focus from the function in the ts file so I can run the otehr stuff first.... – user3390251 Apr 18 '19 at 16:05
  • By the way, with the template given in the question, the input element is visible when the button is visible. If something else is going on that makes the input not visible, please include the relevant code/markup in the question, or make a stackblitz to show the problem. – ConnorsFan Apr 18 '19 at 16:34
0

How about to use a data-attribute with id and get the input from it?

<ng-template #myTemplate let-context="context">
<input [attr.data-group]="context.id" />
<button class="btn" [attr.data-group]="context.id" (click)="focusOnInput($event)"></button>
</ng-template>
<input data-group="1" />
<button class="btn" data-group="1"></button>

<input data-group="2" />
<button class="btn" data-group="2"></button>

<input data-group="3" />
<button class="btn" data-group="3"></button>
// component constructor
constructor(
    private readonly elementRef: ElementRef,
    // ...
  ) {
    // ...
  }

focusOnInput(event: MouseEvent): void {
    const groupId = (<HTMLElement>event.target).dataset.group;
    const input = this.elementRef.nativeElement.querySelector(`input[data-group="${groupId}"]`);
    input.focus();
}
  • this is a clever idea - unfortunately I'm getting an error that it can't bind to "group" since it isn't a known property of button... not sure why... – user3390251 Apr 18 '19 at 15:57
  • Ah. Sorry. Did not tested it. Just updated the template. This is because a regular button does not have that property. But you could use `attr.` to tell angular, you just want to set the html attribute. – Konrad Klockgether Apr 18 '19 at 16:02