Reputation: 127
Angular v5
My search component retrieves data from a service returning a search result promise. On page load my "searchResults" array is empty (= new Array()) until the search is called in page and the promise is returned.
*ngFor is throwing an error because the above mentioned "searchResults" is empty on page load. How do I circumvent this until the search results are populated?
Service:
getSearchResults(searchTerm: string, resourceType: string, pageSize: number = 9999, pageNumber: number = 1): Promise<object> {
const search = {
Term: searchTerm,
ResourceType: resourceType,
PageSize: pageSize,
PageNum: pageNumber,
ModuleId: moduleId
};
const searchHeader = {headers: this.getHttpHeaders()};
const promise = new Promise((resolve, reject): void => {
this.http.post(this.apiRoot, search, searchHeader).toPromise()
.then(response => {
resolve(JSON.parse(response['_body']));
})
.catch(error => {
reject(error);
});
});
return promise;
}
Component:
submitSearch(): void {
this.siteSearchService.getSearchResults(this.searchString, this.selectedResourceType)
.then(response => {
let dto: DTO.SearchResults = <DTO.SearchResults>response;
this.totalHits = dto.TotalHits;
this.searchResults = dto.Results;
}).catch(error => {
console.log(error);
});
}
Template:
<div class="row" *ngIf="searchResults" style="margin:25px;">
<div class="col-xs-12 result-row" *ngFor="let result in searchResults">
<div class="row">
<div class="col-xs-12 col-sm-10">
<a href [href]="result.Url" target="_blank" class="search-result-link">
<h3>{{result.Title}}</h3>
</a>
<p>{{result.Description}}</p>
</div>
<div class="col-xs-12 col-sm-2">
ToDo: Button
</div>
</div>
</div>
</div>
Upvotes: 1
Views: 1855
Reputation: 1123
Just try with *ngIf="searchResults"
and also in your code replace
*ngFor="let result in searchResults"
with *ngFor="let result of searchResults"
Hope that solves your problem
Upvotes: 2
Reputation: 40886
My fix would be to use the async
pipe. This will let Angular know to wait for the results to arrive before trying to loop with ngFor. I would turn searchResults
into an observable that emits results at the end of each search.
In the view, emit an event each time the button is clicked:
<input #searchInput />
<button (click)="searchSubject.next(searchInput.value)">Search</button>
In the component class:
// Will emit each new search term when user clicks search button
searchSubject = new Subject<string>();
// Will trigger the search each time the searchSubject emits:
searchResults = searchSubject
.switchMap(term => this.siteSearchService.getSearchResults(term));
.map(response => response.Results)
.catch(err => console.error(err));
Finally modify the template to use the pipe:
<div *ngFor="let result of searchResults | async">
The async pipe will subscribe to searchResults
and start listening to the click event. Once your component is destroyed, Angular will unsubscribe for you.
Upvotes: 2