Angular 16 (#2007)
* Removed adv, which isn't needed. * Updated zone * Updated to angular 16 * Updated to angular 16 (partially) * Updated to angular 16 * Package update for Angular 16 (and other dependencies) is complete. * Replaced all takeUntil(this.onDestroy) with new takeUntilDestroyed() * Updated all inputs that have ! to be required and deleted all unit tests. * Corrected how takeUntilDestroyed() is supposed to be implemented.
This commit is contained in:
parent
9bc8361381
commit
9c06cccd35
87 changed files with 3964 additions and 20426 deletions
|
|
@ -1,4 +1,13 @@
|
|||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core';
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
ChangeDetectorRef,
|
||||
Component,
|
||||
DestroyRef,
|
||||
inject,
|
||||
Input,
|
||||
OnDestroy,
|
||||
OnInit
|
||||
} from '@angular/core';
|
||||
import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
|
||||
import { BehaviorSubject, Observable, of, Subject } from 'rxjs';
|
||||
import { map, shareReplay, takeUntil } from 'rxjs/operators';
|
||||
|
|
@ -13,6 +22,7 @@ import { UpdateVersionEvent } from 'src/app/_models/events/update-version-event'
|
|||
import { User } from 'src/app/_models/user';
|
||||
import { AccountService } from 'src/app/_services/account.service';
|
||||
import { EVENTS, Message, MessageHubService } from 'src/app/_services/message-hub.service';
|
||||
import {takeUntilDestroyed} from "@angular/core/rxjs-interop";
|
||||
|
||||
@Component({
|
||||
selector: 'app-nav-events-toggle',
|
||||
|
|
@ -21,12 +31,11 @@ import { EVENTS, Message, MessageHubService } from 'src/app/_services/message-hu
|
|||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class EventsWidgetComponent implements OnInit, OnDestroy {
|
||||
@Input() user!: User;
|
||||
@Input({required: true}) user!: User;
|
||||
private readonly destroyRef = inject(DestroyRef);
|
||||
|
||||
isAdmin$: Observable<boolean> = of(false);
|
||||
|
||||
private readonly onDestroy = new Subject<void>();
|
||||
|
||||
/**
|
||||
* Progress events (Event Type: 'started', 'ended', 'updated' that have progress property)
|
||||
*/
|
||||
|
|
@ -53,21 +62,19 @@ export class EventsWidgetComponent implements OnInit, OnDestroy {
|
|||
return EVENTS;
|
||||
}
|
||||
|
||||
constructor(public messageHub: MessageHubService, private modalService: NgbModal,
|
||||
constructor(public messageHub: MessageHubService, private modalService: NgbModal,
|
||||
private accountService: AccountService, private confirmService: ConfirmService,
|
||||
private readonly cdRef: ChangeDetectorRef, public downloadService: DownloadService) {
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.onDestroy.next();
|
||||
this.onDestroy.complete();
|
||||
this.progressEventsSource.complete();
|
||||
this.singleUpdateSource.complete();
|
||||
this.errorSource.complete();
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.messageHub.messages$.pipe(takeUntil(this.onDestroy)).subscribe(event => {
|
||||
this.messageHub.messages$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(event => {
|
||||
if (event.event === EVENTS.NotificationProgress) {
|
||||
this.processNotificationProgressEvent(event);
|
||||
} else if (event.event === EVENTS.Error) {
|
||||
|
|
@ -86,8 +93,8 @@ export class EventsWidgetComponent implements OnInit, OnDestroy {
|
|||
});
|
||||
|
||||
this.isAdmin$ = this.accountService.currentUser$.pipe(
|
||||
takeUntil(this.onDestroy),
|
||||
map(user => (user && this.accountService.hasAdminRole(user)) || false),
|
||||
takeUntilDestroyed(this.destroyRef),
|
||||
map(user => (user && this.accountService.hasAdminRole(user)) || false),
|
||||
shareReplay()
|
||||
);
|
||||
}
|
||||
|
|
@ -187,11 +194,11 @@ export class EventsWidgetComponent implements OnInit, OnDestroy {
|
|||
let data = [];
|
||||
if (messageEvent.name === EVENTS.Info) {
|
||||
data = this.infoSource.getValue();
|
||||
data = data.filter(m => m !== messageEvent);
|
||||
data = data.filter(m => m !== messageEvent);
|
||||
this.infoSource.next(data);
|
||||
} else {
|
||||
data = this.errorSource.getValue();
|
||||
data = data.filter(m => m !== messageEvent);
|
||||
data = data.filter(m => m !== messageEvent);
|
||||
this.errorSource.next(data);
|
||||
}
|
||||
this.activeEvents = Math.max(this.activeEvents - 1, 0);
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
<div class="search">
|
||||
<input #input [id]="id" type="text" inputmode="search" autocomplete="off" formControlName="typeahead" [placeholder]="placeholder"
|
||||
aria-haspopup="listbox" aria-owns="dropdown" aria-expanded="hasFocus && (grouppedData.persons.length || grouppedData.collections.length || grouppedData.series.length || grouppedData.persons.length || grouppedData.tags.length || grouppedData.genres.length)"
|
||||
aria-autocomplete="list" (focusout)="close($event)" (focus)="open($event)" role="search"
|
||||
aria-autocomplete="list" (focusout)="close($event)" (focus)="open($event)" role="search"
|
||||
>
|
||||
<div class="spinner-border spinner-border-sm" role="status" *ngIf="isLoading">
|
||||
<span class="visually-hidden">Loading...</span>
|
||||
|
|
@ -13,90 +13,90 @@
|
|||
</div>
|
||||
<div class="dropdown" *ngIf="hasFocus">
|
||||
<ul class="list-group" role="listbox" id="dropdown">
|
||||
<ng-container *ngIf="seriesTemplate !== undefined && grouppedData.series.length > 0">
|
||||
<ng-container *ngIf="seriesTemplate !== undefined && groupedData.series.length > 0">
|
||||
<li class="list-group-item section-header"><h5 id="series-group">Series</h5></li>
|
||||
<ul class="list-group results" role="group" aria-describedby="series-group">
|
||||
<li *ngFor="let option of grouppedData.series; let index = index;" (click)="handleResultlick(option)" tabindex="0"
|
||||
<li *ngFor="let option of groupedData.series; let index = index;" (click)="handleResultlick(option)" tabindex="0"
|
||||
class="list-group-item" aria-labelledby="series-group" role="option">
|
||||
<ng-container [ngTemplateOutlet]="seriesTemplate" [ngTemplateOutletContext]="{ $implicit: option, idx: index }"></ng-container>
|
||||
</li>
|
||||
</ul>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="collectionTemplate !== undefined && grouppedData.collections.length > 0">
|
||||
<ng-container *ngIf="collectionTemplate !== undefined && groupedData.collections.length > 0">
|
||||
<li class="list-group-item section-header"><h5>Collections</h5></li>
|
||||
<ul class="list-group results">
|
||||
<li *ngFor="let option of grouppedData.collections; let index = index;" (click)="handleResultlick(option)" tabindex="0"
|
||||
<li *ngFor="let option of groupedData.collections; let index = index;" (click)="handleResultlick(option)" tabindex="0"
|
||||
class="list-group-item" role="option">
|
||||
<ng-container [ngTemplateOutlet]="collectionTemplate" [ngTemplateOutletContext]="{ $implicit: option, idx: index }"></ng-container>
|
||||
</li>
|
||||
</ul>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="readingListTemplate !== undefined && grouppedData.readingLists.length > 0">
|
||||
<ng-container *ngIf="readingListTemplate !== undefined && groupedData.readingLists.length > 0">
|
||||
<li class="list-group-item section-header"><h5>Reading Lists</h5></li>
|
||||
<ul class="list-group results">
|
||||
<li *ngFor="let option of grouppedData.readingLists; let index = index;" (click)="handleResultlick(option)" tabindex="0"
|
||||
<li *ngFor="let option of groupedData.readingLists; let index = index;" (click)="handleResultlick(option)" tabindex="0"
|
||||
class="list-group-item" role="option">
|
||||
<ng-container [ngTemplateOutlet]="readingListTemplate" [ngTemplateOutletContext]="{ $implicit: option, idx: index }"></ng-container>
|
||||
</li>
|
||||
</ul>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="libraryTemplate !== undefined && grouppedData.libraries.length > 0">
|
||||
<ng-container *ngIf="libraryTemplate !== undefined && groupedData.libraries.length > 0">
|
||||
<li class="list-group-item section-header"><h5 id="libraries-group">Libraries</h5></li>
|
||||
<ul class="list-group results" role="group" aria-describedby="libraries-group">
|
||||
<li *ngFor="let option of grouppedData.libraries; let index = index;" (click)="handleResultlick(option)" tabindex="0"
|
||||
<li *ngFor="let option of groupedData.libraries; let index = index;" (click)="handleResultlick(option)" tabindex="0"
|
||||
class="list-group-item" aria-labelledby="libraries-group" role="option">
|
||||
<ng-container [ngTemplateOutlet]="libraryTemplate" [ngTemplateOutletContext]="{ $implicit: option, idx: index }"></ng-container>
|
||||
</li>
|
||||
</ul>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="genreTemplate !== undefined && grouppedData.genres.length > 0">
|
||||
<ng-container *ngIf="genreTemplate !== undefined && groupedData.genres.length > 0">
|
||||
<li class="list-group-item section-header"><h5>Genres</h5></li>
|
||||
<ul class="list-group results">
|
||||
<li *ngFor="let option of grouppedData.genres; let index = index;" (click)="handleResultlick(option)" tabindex="0"
|
||||
<li *ngFor="let option of groupedData.genres; let index = index;" (click)="handleResultlick(option)" tabindex="0"
|
||||
class="list-group-item" role="option">
|
||||
<ng-container [ngTemplateOutlet]="genreTemplate" [ngTemplateOutletContext]="{ $implicit: option, idx: index }"></ng-container>
|
||||
</li>
|
||||
</ul>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="tagTemplate !== undefined && grouppedData.tags.length > 0">
|
||||
<ng-container *ngIf="tagTemplate !== undefined && groupedData.tags.length > 0">
|
||||
<li class="list-group-item section-header"><h5>Tags</h5></li>
|
||||
<ul class="list-group results">
|
||||
<li *ngFor="let option of grouppedData.tags; let index = index;" (click)="handleResultlick(option)" tabindex="0"
|
||||
<li *ngFor="let option of groupedData.tags; let index = index;" (click)="handleResultlick(option)" tabindex="0"
|
||||
class="list-group-item" role="option">
|
||||
<ng-container [ngTemplateOutlet]="tagTemplate" [ngTemplateOutletContext]="{ $implicit: option, idx: index }"></ng-container>
|
||||
</li>
|
||||
</ul>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="personTemplate !== undefined && grouppedData.persons.length > 0">
|
||||
<ng-container *ngIf="personTemplate !== undefined && groupedData.persons.length > 0">
|
||||
<li class="list-group-item section-header"><h5>People</h5></li>
|
||||
<ul class="list-group results">
|
||||
<li *ngFor="let option of grouppedData.persons; let index = index;" (click)="handleResultlick(option)" tabindex="0"
|
||||
<li *ngFor="let option of groupedData.persons; let index = index;" (click)="handleResultlick(option)" tabindex="0"
|
||||
class="list-group-item" role="option">
|
||||
<ng-container [ngTemplateOutlet]="personTemplate" [ngTemplateOutletContext]="{ $implicit: option, idx: index }"></ng-container>
|
||||
</li>
|
||||
</ul>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="chapterTemplate !== undefined && grouppedData.chapters.length > 0">
|
||||
<ng-container *ngIf="chapterTemplate !== undefined && groupedData.chapters.length > 0">
|
||||
<li class="list-group-item section-header"><h5>Chapters</h5></li>
|
||||
<ul class="list-group results">
|
||||
<li *ngFor="let option of grouppedData.chapters; let index = index;" (click)="handleResultlick(option)" tabindex="0"
|
||||
<li *ngFor="let option of groupedData.chapters; let index = index;" (click)="handleResultlick(option)" tabindex="0"
|
||||
class="list-group-item" role="option">
|
||||
<ng-container [ngTemplateOutlet]="chapterTemplate" [ngTemplateOutletContext]="{ $implicit: option, idx: index }"></ng-container>
|
||||
</li>
|
||||
</ul>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="fileTemplate !== undefined && grouppedData.files.length > 0">
|
||||
<ng-container *ngIf="fileTemplate !== undefined && groupedData.files.length > 0">
|
||||
<li class="list-group-item section-header"><h5>Files</h5></li>
|
||||
<ul class="list-group results">
|
||||
<li *ngFor="let option of grouppedData.files; let index = index;" (click)="handleResultlick(option)" tabindex="0"
|
||||
<li *ngFor="let option of groupedData.files; let index = index;" (click)="handleResultlick(option)" tabindex="0"
|
||||
class="list-group-item" role="option">
|
||||
<ng-container [ngTemplateOutlet]="fileTemplate" [ngTemplateOutletContext]="{ $implicit: option, idx: index }"></ng-container>
|
||||
</li>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,25 @@
|
|||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChild, ElementRef, EventEmitter, HostListener, Input, OnDestroy, OnInit, Output, TemplateRef, ViewChild } from '@angular/core';
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
ChangeDetectorRef,
|
||||
Component,
|
||||
ContentChild, DestroyRef,
|
||||
ElementRef,
|
||||
EventEmitter,
|
||||
HostListener,
|
||||
inject,
|
||||
Input,
|
||||
OnDestroy,
|
||||
OnInit,
|
||||
Output,
|
||||
TemplateRef,
|
||||
ViewChild
|
||||
} from '@angular/core';
|
||||
import { FormControl, FormGroup } from '@angular/forms';
|
||||
import { Subject } from 'rxjs';
|
||||
import { debounceTime, takeUntil } from 'rxjs/operators';
|
||||
import { KEY_CODES } from 'src/app/shared/_services/utility.service';
|
||||
import { SearchResultGroup } from 'src/app/_models/search/search-result-group';
|
||||
import {takeUntilDestroyed} from "@angular/core/rxjs-interop";
|
||||
|
||||
@Component({
|
||||
selector: 'app-grouped-typeahead',
|
||||
|
|
@ -11,7 +27,7 @@ import { SearchResultGroup } from 'src/app/_models/search/search-result-group';
|
|||
styleUrls: ['./grouped-typeahead.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class GroupedTypeaheadComponent implements OnInit, OnDestroy {
|
||||
export class GroupedTypeaheadComponent implements OnInit {
|
||||
/**
|
||||
* Unique id to tie with a label element
|
||||
*/
|
||||
|
|
@ -24,7 +40,7 @@ export class GroupedTypeaheadComponent implements OnInit, OnDestroy {
|
|||
* Initial value of the search model
|
||||
*/
|
||||
@Input() initialValue: string = '';
|
||||
@Input() grouppedData: SearchResultGroup = new SearchResultGroup();
|
||||
@Input() groupedData: SearchResultGroup = new SearchResultGroup();
|
||||
/**
|
||||
* Placeholder for the input
|
||||
*/
|
||||
|
|
@ -62,7 +78,8 @@ export class GroupedTypeaheadComponent implements OnInit, OnDestroy {
|
|||
@ContentChild('readingListTemplate') readingListTemplate!: TemplateRef<any>;
|
||||
@ContentChild('fileTemplate') fileTemplate!: TemplateRef<any>;
|
||||
@ContentChild('chapterTemplate') chapterTemplate!: TemplateRef<any>;
|
||||
|
||||
private readonly destroyRef = inject(DestroyRef);
|
||||
|
||||
|
||||
hasFocus: boolean = false;
|
||||
isLoading: boolean = false;
|
||||
|
|
@ -70,16 +87,14 @@ export class GroupedTypeaheadComponent implements OnInit, OnDestroy {
|
|||
|
||||
prevSearchTerm: string = '';
|
||||
|
||||
private onDestroy: Subject<void> = new Subject();
|
||||
|
||||
get searchTerm() {
|
||||
return this.typeaheadForm.get('typeahead')?.value || '';
|
||||
}
|
||||
|
||||
get hasData() {
|
||||
return !(this.noResultsTemplate != undefined && !this.grouppedData.persons.length && !this.grouppedData.collections.length
|
||||
&& !this.grouppedData.series.length && !this.grouppedData.persons.length && !this.grouppedData.tags.length && !this.grouppedData.genres.length && !this.grouppedData.libraries.length
|
||||
&& !this.grouppedData.files.length && !this.grouppedData.chapters.length);
|
||||
return !(this.noResultsTemplate != undefined && !this.groupedData.persons.length && !this.groupedData.collections.length
|
||||
&& !this.groupedData.series.length && !this.groupedData.persons.length && !this.groupedData.tags.length && !this.groupedData.genres.length && !this.groupedData.libraries.length
|
||||
&& !this.groupedData.files.length && !this.groupedData.chapters.length);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -92,7 +107,7 @@ export class GroupedTypeaheadComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
|
||||
@HostListener('window:keydown', ['$event'])
|
||||
handleKeyPress(event: KeyboardEvent) {
|
||||
handleKeyPress(event: KeyboardEvent) {
|
||||
if (!this.hasFocus) { return; }
|
||||
|
||||
switch(event.key) {
|
||||
|
|
@ -109,7 +124,7 @@ export class GroupedTypeaheadComponent implements OnInit, OnDestroy {
|
|||
this.typeaheadForm.addControl('typeahead', new FormControl(this.initialValue, []));
|
||||
this.cdRef.markForCheck();
|
||||
|
||||
this.typeaheadForm.valueChanges.pipe(debounceTime(this.debounceTime), takeUntil(this.onDestroy)).subscribe(change => {
|
||||
this.typeaheadForm.valueChanges.pipe(debounceTime(this.debounceTime), takeUntilDestroyed(this.destroyRef)).subscribe(change => {
|
||||
const value = this.typeaheadForm.get('typeahead')?.value;
|
||||
|
||||
if (value != undefined && value != '' && !this.hasFocus) {
|
||||
|
|
@ -127,17 +142,12 @@ export class GroupedTypeaheadComponent implements OnInit, OnDestroy {
|
|||
});
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.onDestroy.next();
|
||||
this.onDestroy.complete();
|
||||
}
|
||||
|
||||
onInputFocus(event: any) {
|
||||
if (event) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
|
||||
this.openDropdown();
|
||||
return this.hasFocus;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
[minQueryLength]="2"
|
||||
initialValue=""
|
||||
placeholder="Search…"
|
||||
[grouppedData]="searchResults"
|
||||
[groupedData]="searchResults"
|
||||
(inputChanged)="onChangeSearch($event)"
|
||||
(clearField)="clearSearch()"
|
||||
(focusChanged)="focusUpdate($event)"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,15 @@
|
|||
import { DOCUMENT } from '@angular/common';
|
||||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, Inject, OnDestroy, OnInit, ViewChild } from '@angular/core';
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
ChangeDetectorRef,
|
||||
Component, DestroyRef,
|
||||
ElementRef,
|
||||
inject,
|
||||
Inject,
|
||||
OnDestroy,
|
||||
OnInit,
|
||||
ViewChild
|
||||
} from '@angular/core';
|
||||
import { NavigationEnd, Router } from '@angular/router';
|
||||
import { fromEvent, Subject } from 'rxjs';
|
||||
import { debounceTime, distinctUntilChanged, filter, takeUntil, tap } from 'rxjs/operators';
|
||||
|
|
@ -17,6 +27,7 @@ import { ImageService } from 'src/app/_services/image.service';
|
|||
import { NavService } from 'src/app/_services/nav.service';
|
||||
import { ScrollService } from 'src/app/_services/scroll.service';
|
||||
import { SearchService } from 'src/app/_services/search.service';
|
||||
import {takeUntilDestroyed} from "@angular/core/rxjs-interop";
|
||||
|
||||
@Component({
|
||||
selector: 'app-nav-header',
|
||||
|
|
@ -24,9 +35,10 @@ import { SearchService } from 'src/app/_services/search.service';
|
|||
styleUrls: ['./nav-header.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class NavHeaderComponent implements OnInit, OnDestroy {
|
||||
export class NavHeaderComponent implements OnInit {
|
||||
|
||||
@ViewChild('search') searchViewRef!: any;
|
||||
private readonly destroyRef = inject(DestroyRef);
|
||||
|
||||
isLoading = false;
|
||||
debounceTime = 300;
|
||||
|
|
@ -48,7 +60,6 @@ export class NavHeaderComponent implements OnInit, OnDestroy {
|
|||
backToTopNeeded = false;
|
||||
searchFocused: boolean = false;
|
||||
scrollElem: HTMLElement;
|
||||
private readonly onDestroy = new Subject<void>();
|
||||
|
||||
constructor(public accountService: AccountService, private router: Router, public navService: NavService,
|
||||
public imageService: ImageService, @Inject(DOCUMENT) private document: Document,
|
||||
|
|
@ -57,7 +68,7 @@ export class NavHeaderComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.scrollService.scrollContainer$.pipe(distinctUntilChanged(), takeUntil(this.onDestroy), tap((scrollContainer) => {
|
||||
this.scrollService.scrollContainer$.pipe(distinctUntilChanged(), takeUntilDestroyed(this.destroyRef), tap((scrollContainer) => {
|
||||
if (scrollContainer === 'body' || scrollContainer === undefined) {
|
||||
this.scrollElem = this.document.body;
|
||||
fromEvent(this.document.body, 'scroll').pipe(debounceTime(20)).subscribe(() => this.checkBackToTopNeeded(this.document.body));
|
||||
|
|
@ -86,11 +97,6 @@ export class NavHeaderComponent implements OnInit, OnDestroy {
|
|||
this.cdRef.markForCheck();
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.onDestroy.next();
|
||||
this.onDestroy.complete();
|
||||
}
|
||||
|
||||
logout() {
|
||||
this.accountService.logout();
|
||||
this.navService.hideNavBar();
|
||||
|
|
@ -109,7 +115,7 @@ export class NavHeaderComponent implements OnInit, OnDestroy {
|
|||
this.searchTerm = val.trim();
|
||||
this.cdRef.markForCheck();
|
||||
|
||||
this.searchService.search(val.trim()).pipe(takeUntil(this.onDestroy)).subscribe(results => {
|
||||
this.searchService.search(val.trim()).pipe(takeUntilDestroyed(this.destroyRef)).subscribe(results => {
|
||||
this.searchResults = results;
|
||||
this.isLoading = false;
|
||||
this.cdRef.markForCheck();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue