Перезагрузка дочернего компонента при изменении переменных в родительском компоненте. Angular2

У меня есть MasterComponent, который загружает заголовок, нижний колонтитул, боковую панель и т.д. В заголовке есть раскрывающийся список, параметры которого устанавливаются после входа пользователя в систему. Я хочу, чтобы заголовок был постоянным, даже если я перемещаюсь по разным маршрутам, в которых загружаются разные дочерние компоненты., Означает, что выбранный параметр не должен изменяться и значение раскрывающегося списка должно быть доступно во всех дочерних компонентах. При изменении значения раскрывающегося списка текущий дочерний компонент должен быть обновлен/перезагружен.

Как мне подойти к этой проблеме? Я хочу, чтобы событие-слушатель было функциональным. Как только модель из MasterComponent изменится, перезагрузите текущий дочерний компонент. При обновлении переменной MasterComponent переменная ChildComponent будет прослушивать обновление и запускать некоторую функцию или снова вызывать некоторый API и перезагружать ChildComponent.

// routes
const appRoutes: Routes = [
    {
        path: '',
        redirectTo: 'login',
        pathMatch: 'full',
    },
    {   path: 'login', component: LoginComponent },
    {   path: 'logout', component: LogoutComponent },
    {
        path: '',
        component: MasterComponent,
        canActivate: [AuthGuard],
        children: [
            { path: 'record/create', component: RecordCreateComponent }, // create record for selectedRestaurant in MasterComponent
            { path: 'record/', component: RecordComponent }, // shows all record of current selectedRestaurant in MasterComponent
            { path: 'record/:id/update', component:RecordUpdateComponent }, // show form to edit record having id
            { path: 'record/:id', component: RecordComponent }, // show record details having id
        ]
    },
    { path: '**', redirectTo: 'login' }
];
// MasterComponent
@Component({
    selector: 'master',
    templateUrl: templateUrl,
    styleUrls:[styleUrl1]

})
export class MasterComponent implements AfterViewInit, OnInit{
    restaurants: Array<Restaurant> = [];
    user:User;
    selectedRestaurant: Restaurant;

    constructor(private router: Router, private storageHelper:StorageHelper){
    }
    ngAfterViewInit() {
    }
    ngOnInit(){
        this.user = JSON.parse(this.storageHelper.getItem('user'));
        this.restaurants = this.user.restaurants;
        this.selectedRestaurant = this.restaurants[0];
        this.router.navigate(['/record/' + this.selectedRestaurant.id]);
    }
    onRestaurantChange(){
        this.router.navigate(['/record/' + this.selectedRestaurant.id]);
    }
    createRecord(){
    }
}

enter image description here

Ответ 1

Используйте @Input для передачи ваших данных дочерним компонентам, а затем используйте ngOnChanges (https://angular.io/api/core/OnChanges), чтобы увидеть, изменился ли этот @Input на лету.

Ответ 2

В Angular для обновления компонента, включая его шаблон, есть прямое решение этого вопроса, имеющее свойство @Input в вашем ChildComponent и добавленное в ваш @Component декоратор changeDetection: ChangeDetectionStrategy.OnPush следующим образом:

import { ChangeDetectionStrategy } from '@angular/core';

@Component({
    selector: 'master',
    templateUrl: templateUrl,
    styleUrls:[styleUrl1],
    changeDetection: ChangeDetectionStrategy.OnPush    
})

export class ChildComponent{
  @Input() data: MyData;
}

Это выполнит всю работу по проверке изменения входных данных и выполнению повторной визуализации компонента.

Ответ 3

обновление @Vladimir Tolstikov ответа

Создайте дочерний компонент, который использует ngOnChanges.

ChildComponent.ts ::

import { Component, OnChanges, Input } from '@angular/core';
import { ActivatedRoute } from '@angular/router';

@Component({
  selector: 'child',
  templateUrl: 'child.component.html',
})

export class ChildComponent implements OnChanges {
  @Input() child_id;

  constructor(private route: ActivatedRoute) { }

  ngOnChanges() {
    // create header using child_id
    console.log(this.child_id);
  }
}

теперь используйте его в шаблоне MasterComponent и передавайте данные в ChildComponent, например:

<child [child_id]="child_id"></child>

Ответ 4

Вы можете использовать @input с ngOnChanges, чтобы увидеть изменения, когда они произошли.

ссылка: https://angular.io/api/core/OnChanges

(Или)

Если вы хотите передавать данные между несколькими компонентами или маршрутами, тогда используйте Rxjs.

Service.ts

import { Injectable } from '@angular/core';
import { Observable, Subject } from 'rxjs';

@Injectable({ providedIn: 'root' })
export class MessageService {
  private subject = new Subject<any>();

  sendMessage(message: string) {
    this.subject.next({ text: message });
  }

  clearMessages() {
    this.subject.next();
  }

  getMessage(): Observable<any> {
    return this.subject.asObservable();
  }
}

Component.ts

import { Component, OnDestroy } from '@angular/core';
import { Subscription } from 'rxjs';

import { MessageService } from './_services/index';

@Component({
  selector: 'app',
  templateUrl: 'app.component.html'
})

export class AppComponent implements OnDestroy {
  messages: any[] = [];
  subscription: Subscription;

  constructor(private messageService: MessageService) {
    // subscribe to home component messages
    this.subscription = this.messageService.getMessage().subscribe(message => {
      if (message) {
        this.messages.push(message);
      } else {
        // clear messages when empty message received
        this.messages = [];
      }
    });
  }

  ngOnDestroy() {
    // unsubscribe to ensure no memory leaks
    this.subscription.unsubscribe();
  }
}

Ссылка: http://jasonwatmore.com/post/2019/02/07/angular-7-communicating-between-components-with-observable-subject