Fel
Fel

Reputation: 4818

Emit search input value to child components in Angular 2

In an Angular 2 app, I have an HTML search input whose value I want to send to 3 child components, only if the user stops typing for 300ms and he typed something different than what input contained. I've read some articles on the Internet and all of them mention the use of Subject, debounceTime and distinctUntilChanged operators. Following one of the tutorials, I ended up with the following code:

PARENT COMPONENT:

// Subject to emit an observable
public searchUpdated: Subject <string> = new Subject<string>();

@Output() searchChangeEmitter: EventEmitter <any> = new EventEmitter <any>();

constructor() {
  [.......]
  this.searchChangeEmitter = <any>this.searchUpdated.asObservable()
    .debounceTime(300)
    .distinctUntilChanged(); // accept only relevant chars
}

onSearchType(value : string) {
  this.searchUpdated.next(value); // Emit the changed value to the subscribers
}

PARENT TEMPLATE:

<input class="input-group-field" type="search" id="inputSearch" name="inputSearch" (keyup)="onSearchType($event.target.value)">

I want to pass the emitted value to the child components but I'm feeling a little lost. I've tried this but it didn't work:

PARENT TEMPLATE

<app-object-tree [searchFilter]="searchChangeEmitter"></app-object-tree>

(And, in the child component 'app-object-tree', create the @Input 'searchFilter' and subscribe to it to try to get the value.)

It makes more sense to me to create a service, provide it in the parent component and subscribe to it on the child components, but I don't know how to call the service 'setter' function after applying the 'debounceTime' and 'distinctUntilChanged' operations.

Thanks a lot, and sorry if I didn't explain myself correctly, I'm still trying to tie all the Subject/Observable concepts in my mind.

Upvotes: 3

Views: 3198

Answers (1)

JoannaFalkowska
JoannaFalkowska

Reputation: 3677

Why do you need an observable or EventEmitter for this? I don't think it's possible to emit events TO children. But you can simply pass a variable. In parent controller:

searchValue: string;
private _searchSubject: Subject<string> = new Subject();

constructor() {
  [.......]
  this._searchSubject
    .debounceTime(200)
    .distinctUntilChanged()
    .subscribe(result => {
      this.searchValue = result;
    });
}

onSearchType(value : string) {
  this._searchSubject.next(value);
}

In parent template:

<input class="input-group-field" type="search" id="inputSearch" name="inputSearch" (keyup)="onSearchType($event.target.value)">
<app-object-tree [searchFilter]="searchValue"></app-object-tree>

The children's @Input value (searchFilter) will now update every time the searchValue in parent changes. There's no need to observe anything in children, it will just get updated.

Upvotes: 2

Related Questions