jen
jen

Reputation: 357

Subscribe to child component's Observable (valueChanges)

I thought to have a simple problem, but i am having a hard time finding confirmation if my solution is "correct"

I have a child component SearchComponent with a formControl

@Component({
    selector : "my-search",
    inputs : ["placeholder"],
    template : `
      <div class="searchForm">
        <input type="text" [placeholder]="placeholder" [formControl]="search"/>
      </div>
    `
})
export class SearchComponent {

    search = new FormControl();
    public searchValues : Observable<string>;


    constructor() {
        this.searchValues  = this.search.valueChanges
            .debounceTime(400) 
            .distinctUntilChanged(); 
    }

}

I am using this in the parent component's template

<div class="col-md-2 sidebar">
    <my-search [placeholder]="'search'"></my-search>
</div>

I now want to subscribe to the searchValues Observable from within the parent. The best i came up with is:

export class MyListComponent implements AfterContentInit {

    @ViewChild(SearchComponent) searchComponent: SearchComponent;

    constructor(private myService: MyService ) {

    }

    ngAfterContentInit() {
        this.searchComponent.searchValues.subscribe(s=>this.search(s))
    }

    private search(s: string) {
        this.foos = this.myService.find(s); 
    }

    foos: Observable<[Foo]>; // used on a ngFor | async

}

Is this recommended approach? Is there no better way to define the contract between the components (like can be done with @Input and @Output)?

Upvotes: 2

Views: 10141

Answers (1)

Adrian F&#226;ciu
Adrian F&#226;ciu

Reputation: 12572

You could easily use @Output for this. In the search component you could add one like:

@Output() searchEvent: EventEmitter = new EventEmitter();

Then subscribe to the text changes and (re)emit them:

this.search.valueChanges
        .debounceTime(400) 
        .distinctUntilChanged()
        .subscribe((event) => this.searchEvent.emit(event));

After that you have the Output that you can use in any parent component. Without any need for a component reference (ViewChild).

Edit

One way to use this would be to have a Subject in the parent component that you push changes to updateStream = new Subject() and the event handler (searchEvent) = "updateStream.next($event)".

Then you can create the Observable like:

foo = updateStream.flatMap((s) => myService.find(s))

Upvotes: 3

Related Questions