Please look at my component below the purpose to is to listen on changes to an input, which it does and then emit the value to the parent component. I created a pipe to only emit every so often and therby minimize the calls to the api, for some reason even though I can see through various console.log
statements that it goes in the pipe, it emits the value on every change. What is it that I am missing:
import {ChangeDetectionStrategy, Component, EventEmitter, Input, OnChanges, OnInit, Output, KeyValueDiffers, DoCheck, KeyValueDiffer} from '@angular/core';
import {BehaviorSubject, Observable, of} from "rxjs";
import {debounceTime, distinctUntilChanged, map, skip, switchMap, takeUntil, tap} from "rxjs/operators";
@Component({
selector: 'core-ui-typeahead-filter',
changeDetection: ChangeDetectionStrategy.OnPush,
templateUrl: './typeahead-filter.component.html',
})
export class TypeaheadFilterComponent implements DoCheck {
@Input() id: string;
@Input() name: string;
@Input() caption: string;
@Input() placeholder: string;
@Input() cssClass: string;
@Input() cssStyle: string;
@Input() function: any;
@Input() data: Observable<string[]>;
differ: any;
detectChange: string = '';
// term$ = new BehaviorSubject<string>('');
text$ = new Observable<string>();
@Output() onTypeahead: EventEmitter<any> = new EventEmitter<any>();
@Output() onSelect: EventEmitter<any> = new EventEmitter<any>();
constructor(private differs: KeyValueDiffers) {
this.differ = this.differs.find({}).create();
}
handleTypeahead = (text$: Observable<string>) =>
text$.pipe(
distinctUntilChanged(),
debounceTime(500),
).subscribe((value) => {
this.onTypeahead.emit(of(value))
})
handleSelectItem(item) {
this.onSelect.emit(item);
}
ngDoCheck() {
const change = this.differ.diff(this);
if (change) {
change.forEachChangedItem(item => {
if (item.key === 'detectChange'){
console.log('item changed', item)
this.text$ = of(item.currentValue);
this.handleTypeahead(this.text$);
}
});
}
}
}
More background: There is an ngModel on the input linked to detectChange
when it changes then the ngDoCheck
is called and executes. Everything is done in observables so in the parent I can subscribe to the incoming events. EDIT ------------------------------------------------------------------- Tried the following solution based on my understanding of @ggradnig answer, sadly it skips over my pipe something seems wrong with it, really not sure what:
handleTypeahead = (text$: Observable<string>) => {
this.test.subscribe(this.text$);
this.test.pipe(
distinctUntilChanged(),
debounceTime(500),
// switchMap(value => text$)
).subscribe((value) => {
tap(console.log('im inside the subscription',value))
this.onTypeahead.emit(value)
})
}
handleSelectItem(item) {
this.onSelect.emit(item);
}
ngDoCheck() {
const change = this.differ.diff(this);
if (change) {
change.forEachChangedItem(item => {
if (item.key === 'detectChange'){
console.log('item changed', item)
this.text$ = of(item.currentValue);
this.handleTypeahead(this.test);
}
});
}
}
}
You can do the following -
export class TypeaheadFilterComponent implements DoCheck {
@Input() id: string;
@Input() name: string;
@Input() caption: string;
@Input() placeholder: string;
@Input() cssClass: string;
@Input() cssStyle: string;
@Input() function: any;
@Input() data: Observable<string[]>;
differ: any;
detectChange: string = '';
// term$ = new BehaviorSubject<string>('');
text$ = new BehaviorSubject<string>('');
serachTerm$: Observable<string>;
@Output() onTypeahead: EventEmitter<any> = new EventEmitter<any>();
@Output() onSelect: EventEmitter<any> = new EventEmitter<any>();
constructor(private differs: KeyValueDiffers) {
this.differ = this.differs.find({}).create();
}
// handleTypeahead = (text$: Observable<string>) =>
// text$.pipe(
// distinctUntilChanged(),
// debounceTime(500),
// ).subscribe((value) => {
// this.onTypeahead.emit(of(value))
// })
ngOnInit() {
this.serachTerm$ = this.text$
.pipe(
distinctUntilChanged(),
debounceTime(500),
//filter(), //use filter operator if your logic wants to ignore certain string like empty/null
tap(s => this.onTypeahead.emit(s))
);
}
handleSelectItem(item) {
this.onSelect.emit(item);
}
ngDoCheck() {
const change = this.differ.diff(this);
if (change) {
change.forEachChangedItem(item => {
if (item.key === 'detectChange'){
console.log('item changed', item)
this.text$.next(item.currentValue);
}
});
}
}
}
Now, at the bottom of your template put the following line -
<ng-container *ngIf="searchTerm$ | async"></ng-container>
Having this line will keep your component code free form managing the subscription [ie need not to subscribe/unsubscribe]; async pipe will take care of it.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.