<div class="dropdownContainer" placeholder="test" (click)="ShowDropDown()" />
<div #tref *ngIf="showDropDown == 1" class="dropdownList" (focusout)="HideDropDown()" style="border:1px solid black;" >this is my test</div>
After clicking the dropDownContainer i would like the dropdownList to appear and have focus put on it.
I Have tried using
@ViewChild("tref", {read: ElementRef}) tref: ElementRef;
method, but it returns undefined because that element doesnt exist in the DOM until the above div
is clicked. How can I autofocus on a dynamic NON INPUT DOM object?
EDIT Updated my code per suggestions, this still will not autofocus on the div.
@ViewChild("tref") tref: ElementRef;
ShowDropDown() {
this.showDropDown = 1;
this.tref.nativeElement.focus();
console.log(this.tref);
}
HideDropDown(){
console.log('test out')
this.showDropDown = 0;
}
<input #tref class="dropdownContainer" placeholder="george" (click)="ShowDropDown()" />
<div tabindex="-1" (focusout)="HideDropDown()" [hidden]="showDropDown == 0" class="dropdownList" style="border:1px solid black;" >this is my test</div>
ANSWER TO THE PROBLEM Two fold answer.
1) DIVS cannot have focus unless they have tabindex. Stack answer
2)I need to include setTimeout(() => this.tref.nativeElement.focus(), 1);
because an element that is hidden
is not automatically ready to receive focus.
3)*ngIf and hidden both worked, once i put in the above fixes
Cleaned up code
import { Component, ElementRef , ViewChild } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.less']
})
export class AppComponent {
constructor() {
}
showDropDown = 0;
@ViewChild("tref") tref: ElementRef;
ShowDropDown() {
this.showDropDown = 1;
setTimeout(() => this.tref.nativeElement.focus(), 1);
}
HideDropDown(){
this.showDropDown = 0;
}
test(){ console.log('works');}
}
<div tabindex="-2" class="dropdownContainer" placeholder="george" (click)="ShowDropDown()" ></div>
<div tabindex="-1" #tref [hidden]="showDropDown == 0" class="dropdownList" style="border:1px solid black;" (click)="test()" (focusout)="HideDropDown()">this is my test</div>
You can focus the dropdown element as soon as it becomes visible, with the help of ViewChildren
and the QueryList.changes
event. This technique works no matter how long it takes for the element to appear in the view.
In the template, give a tabindex
attribute to the dropdown div
:
<div class="dropdownContainer" (click)="showDropDown = true">
Click here to show the dropdown
</div>
<div #dropDownDiv *ngIf="showDropDown" tabindex="1" class="dropdownList" (focusout)="showDropDown = false">
This is the dropdown element
</div>
In code, retrieve the dropdown element with ViewChildren
, and set the QueryList.changes
event handler in ngAfterViewInit
. When you are notified that the element has become visible, you can set the focus on it:
showDropDown = false;
@ViewChildren("dropDownDiv") private dropDownDivList: QueryList<ElementRef>;
ngAfterViewInit() {
this.dropDownDivList.changes.subscribe((list: QueryList<ElementRef>) => {
if (list.length > 0) {
list.first.nativeElement.focus();
}
});
}
See this stackblitz for a demo.
Change from *ngIf="showDropDown"
to [hidden]="! showDropDown"
and you should be able to use @ViewChild inside the component and prevent the "undefiend" issue.
If that still didn't work, you could always pass the element to the component through the click event by changing the click to this (click)="ShowDropDown(tref)"
. Note that in order for this to work, you'd still need to change *ngIf to [hidden].
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With