0
votes

I have two components, app.component and encours.component, I have a select in my app.component's navbar which need to send value to encours.component on each changing. I can get value the first time, but after, I can't get nothing. I have a service called dataService for the communication, and I use a router outlet for the routing, so I can't pass data from the router-outlet tag I have tried to implement the ngOnChange method in encours.component, but it doesn't work.

Here is my service code :

@Injectable()
export class DataService{

  private serviceSource = new BehaviorSubject(3);
  currentService = this.serviceSource.asObservable();

  constructor(){}

  changeService(service: number){
    this.serviceSource.next(service);
  }

}

Here is my app.component.html code :

<nav class="navbar navbar-expand-lg navbar-light bg-light">

  <a class="navbar-brand" href="#">SAFRAN</a>
  <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
    <span class="navbar-toggler-icon"></span>
    <form class="form-inline my-2 my-lg-0" *ngIf="showSelect">
      <select class="custom-select" id="service" #serviceSelect [(ngModel)]="service" name="service" (change)="setSelection(serviceSelect.value)">
        <option *ngFor = "let service of listeServices" value="{{service.id}}">{{service.nom}}</option>
      </select>
    </form>
</nav>

<router-outlet>
</router-outlet>

Here is my app.component.ts code :

export class AppComponent implements OnInit{

  public listeServices: any;
  service: number;

  constructor(private router:Router, private serviceServ : ServiceService, private data : DataService) {
    router.events.forEach((event) => {
      if(event instanceof NavigationStart) {
        //I get some data from an API
        this.getServices();
        //I show the select only if the route is encours
        this.showSelect = event.url === "/encours";
      }
    });
  }

  ngOnInit(): void {
    this.data.currentService.subscribe(service => this.service = service)
  }

  public setSelection(selectedValue: any): void {
    this.service = selectedValue;
    this.data.changeService(selectedValue);
  }

Here encours.component.html file :

<table *ngIf="listeFamilles">
  <tbody>
    <tr *ngFor="let f of listeFamilles">
      <th style="vertical-align: middle; padding-left: 10px;">{{ f.nom }}</th>
      <td  id="{{f.nom}}"  style="vertical-align: top;"></td>
    </tr>
  </tbody>
</table>

And finally, my encours.component.ts :

export class EncoursComponent implements OnInit, OnChanges{

  service : number;

  constructor(private serviceFam: FamillesService, private serviceOpe: OperationsService, private serviceVar: VarianteService, private serviceAff: AffaireService, private serviceAffecter: AffecterService, private data : DataService) {
    this.data.currentService.subscribe(service => this.service = service);
  }

  //This function is never called
  ngOnChanges(changes: SimpleChanges): void {
    console.log(changes);
  }
2
You should post the code to your template because your problem is not reproducible without it - JamieT
@Jamie it's done - Maxime Alza
Ok, I now understand the problem better. Are you specifically wanting ngOnChanges() to fire or do you only care about when the value of currentService in the DataService changes? - JamieT
I would like to refresh my encours.component.ts at each changing, with the new value in service of EnCoursComponent - Maxime Alza
the subscription you have in encours.component.ts will be called whenever that value changes. Change the subscription line in the constructor to console log this update this.data.currentService.subscribe(service => cosole.log(service)); and you should be able to see this, yes? - JamieT

2 Answers

2
votes

The subscription you have in encours.component.ts to the DataService's data field will be called whenever that value changes so this component actually is already receiving this data. Implementing the interface ngOnChanges would be verbose for a use case like this as the component is already receiving the updated value in the subscription you have in the constructor.

Change the subscription line in the constructor to console log this update:

this.data.currentService.subscribe(service => {
    console.log(service);
    this.service = service;
}); 

and now are be able to see that this is actually already the case.

Extra work is required if you want to (in my opinion, verbosely) fire onChanges() and handle the updates there. onChanges() only fires when an property with an @Input attribute changes. This would require you to pass the value of the DataService's currentService as an @Input through the template which is achievable via async pipe.

An example of implementing this can be found here: https://www.concretepage.com/angular-2/angular-2-4-onchanges-simplechanges-example. Official documentation here: https://angular.io/api/core/OnChanges.

0
votes
// This function is never called
  ngOnChanges(changes: SimpleChanges): void {
    console.log(changes);
  }

Of course, ngOnChanges hook is called when any data-bound property changes, So if It would only work if the component EncoursComponent would have a @Input property.