Reputation: 135
I'm working on Angular 9 and want to access an input field after clicking on a button. right now it gives me undefined. I have tried @ViewChild
and @ViewChildren
because I'm using ngIf
.
Template.html file
<div class="search-input" #searchDiv *ngIf="searchActive">
<input
#searched
autofocus
type="text"
class="search-term"
placeholder="Search"
[(ngModel)]="searchTerms"
(ngModelChange)="applySearch()"
/>
<button (click)="toggleSearch(!searchActive)">
<span class="material-icons"> search </span>
</button>
<ul class="search-list">
<li *ngFor="let result of results">
<a [routerLink]="['/', 'video', 'details', result._id]">{{
result.title ? result.title : ''
}}</a>
</li>
</ul>
</div>
Template.ts file
import { Component, OnInit,AfterViewInit,ElementRef,ViewChild,ViewChildren } from '@angular/core';
import { UserService } from '../../../user.service';
import { VideoService } from '../../../services/video.service';
import { Subject } from 'rxjs';
import { distinctUntilChanged, debounceTime } from 'rxjs/operators';
import { Router } from '@angular/router';
@Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.css'],
})
export class HeaderComponent implements OnInit,AfterViewInit{
searchActive: boolean = false;
@ViewChildren('searched') searchElement: ElementRef;
@ViewChildren("searched") input: ElementRef;
user;
subject = new Subject<string>();
results = [];
searchTerms;
loggedIn: Boolean = false;
constructor(
private userService: UserService,
private videoService: VideoService,
private router: Router
) {
this.user = this.userService.getUser();
this.loggedIn = this.userService.isAuthenticated();
}
ngOnInit() {
console.log('on init', this.input); //undefined
this.subject
.pipe(debounceTime(400), distinctUntilChanged())
.subscribe((value) => {
this.router.navigate(['search'], { queryParams: { term: value } });
});
}
ngAfterViewInit() {
console.log('on after', this.input); //undefined
}
toggleSearch(toggledata) {
this.searchActive = toggledata;
this.results = [];
this.searchTerms = '';
console.log(this.input) //undefined
console.log(this.searchElement.nativeElement) //undefined
}
applySearch() {
const searchText = this.searchTerms;
this.subject.next(searchText);
this.searchElement.nativeElement.focus(); //undefined
}
menuButtonClick(button){
if(button === "history"){
this.router.navigate(['history'])
}
}
}
Upvotes: 0
Views: 6534
Reputation: 8269
Use ViewChild
since you're only searching for 1 element ID.
If adding { static: true }
or { static: false }
in your ViewChild
options doesn't work as what is stipulated on Angular Static Query Migration Documentation
Use ChangeDetectorRef
instead:
@Component({...})
export class AppComponent {
@ViewChild('searchInput') input: ElementRef;
isShow: boolean = false;
constructor(private cdr: ChangeDetectorRef) {}
toggle(): void {
this.isShow = !this.isShow;
this.cdr.detectChanges(); // Detects changes which this.isShow is responsible on showing / hiding
// the element you're referencing to in ViewChild
if (this.isShow) // If element is shown, console the referenced element
console.log(this.input);
}
}
Have created a Stackblitz Demo for your reference
Upvotes: 2