Search code examples
angulartypescriptdata-bindingangular2-componentsangular2-inputs

Two way data binding between multiple components in angular2?


I have two components HomePageComponent and StudentResultsComponent. I have an input in HomePageComponent that when I type, I want the value to be in my StudentResultsComponent input.

I thought of creating a separate component for the input and calling them in both components, but the value is not being updated in my StudentsResultsComponent when I start typing in HomePageComponent. Heres my code:

Career-Search-Component.html

<input
  #input
  type        ="text"
  id          ="searchInput"
  class       ="input-student-search validate filter-input"
  placeholder ="Search by a career (Software Engineer,Web Developer,Geologist, Geogropher etc.)"
  [(ngModel)] ="query"
>

Career-Search.component.ts

import {Component,OnInit,Input,EventEmitter} from '@angular/core';
@Component({
  selector: 'career-search',
  templateUrl: 'career-search.component.html'
})
export class CareerSearchComponent implements OnInit {
  @Input() public query: string;
  constructor() {}

  ngOnInit() {}

}

HomePageComponent.component.html

<career-search></career-search>
<button class="submit" [routerLink]="['/students']">Search</button>

Students-result.component.html

<career-search></career-search>

The reason why i need to pass the data from the homepage component is because I can then use the data to query it and show results based on the value being passed from the other component.

Please help.

Thanks


Solution

  • If your two components don't have any other connection the only way I know of is to use a service. The link provided by AJT_82 has an example for it and here is the smallest example I can think of:

    import {Component, Injectable, EventEmitter} from '@angular/core';
    
    @Injectable()
    export class InputService {
    
      public inputEvents: EventEmitter<string> = new EventEmitter();
    
      public inputChanged(val: string) {
        this.inputEvents.emit(val);
      }
    }
    
    @Component({
      selector: 'observer',
      template: `
        <p>Input value: {{ myValue }}</p>
    `
    })
    export class ObserverComponent implements OnDestroy {
    
      private myValue: string;
      private subscription: Subscription;
    
      constructor(private service: InputService) {
        this.subscription = this.service.inputEvents.subscribe((newValue) => {
          this.myValue = newValue;
        })
      }
    
      ngOnDestroy(): void {
        this.subscription.unsubscribe();
      }
    }
    
    @Component({
      selector: 'observable',
      template: `
        <input [(ngModel)]="inputValue" />
    `
    })
    export class ObservableComponent {
    
      private _inputValue: string;
    
      constructor(private service: InputService) {}
    
      public get inputValue(): string {
        return this._inputValue;
      }
    
      public set inputValue(val: string) {
        this._inputValue = val;
        this.service.inputChanged(val);
      }
    }
    
    @Component({
      selector: 'app-root',
      template: `
    
        <observable></observable>
        <observer></observer>
    
    `
    })
    export class AppComponent {
    }

    Explanation:

    The Observable Component stores the input-Value via two-way data binding. Within the setter we not only store the value, but also tell the service the value has changed. The service will then emit an inputChanged event, which the Observer subscribes to. It can then use the value however it likes.