与根 AppComponent 交互 - Angular

Interacting with root AppComponent - Angular

我正在尝试在组件 SettingsComponent 中实现功能,用户按下按钮,根 AppComponent 中的横幅将发生变化。

customBanner():void{
  this.changeBanner = true;
}

当用户按下 SettingsComponent 中的按钮时调用上述函数。该应用程序的横幅位于根 AppComponent

<div *ngIf ="!changeBanner">
    <h2 class="main-header"><img src = "../../../assets/images/banner.jpg" style="max-height:40px"></h2>
</div>
<div *ngIf ="changeBanner">
    <h2>Custom Banner</h2>
</div>
<router-outlet></router-outlet>

changeBannerAppComponent的变量。我试图在用户按下 SettingsComponent 中的按钮时获取它,AppComponent 中的变量 changeBanner 将被更改。

现在我正在尝试这个:

export class AppComponent implements AfterViewInit {
 changeBanner = false; 
 @ViewChild(SettingsComponent)
 private settings:SettingsComponent; 

 ngAfterViewInit(){
     this.changeBanner = this.settings.changeBanner; 
 }
}

就在我按下 settings 页面上的任何内容之前,我收到错误消息

Cannot read property 'changeBanner' of undefined

谈论this.settings.changeBanner

如果我按下一个按钮,什么也不会发生。我不确定我是否以正确的方式进行此操作。

SettingsComponent 的实例需要是 AppComponent 的直接子级,即在 AppComponent 的视图中需要有一个 <my-settings></my-settings> 或类似的。否则这将无法工作。

除此之外,您应该使用模板绑定或中间服务将数据从一个组件移动到另一个组件。

基本上,主题是不同组件之间的通信。通常,当子组件想要与父组件通信时,您会通过 @Output 属性.

使用事件绑定

但在您的情况下,横幅 属性 似乎是许多组件之间的共享状态。在这种情况下,最好创建一个保存该状态的服务。所有应该更改横幅的组件都获得此 BannerService 的实例。 BannerService 有一个 Observable,它会在横幅更改时发出更改。 AppComponent 然后可以订阅该 Observable 并相应地更改横幅。

另一种管理共享状态的替代方案是 ngrx,它很棒但学习曲线相当陡峭。

去掉 AppComponent 中的 @ViewChild(SettingsComponent)。

在 AppComponent 中创建一个名为 bannerChanged(){ this.changeBanner = !this.changeBanner;}

的函数

在您的 html 应用程序组件中执行此操作:

<app-settings  (bannerChanged)="bannerChanged($event)"></app-settings>

然后在您的 SettingsComponent 中有这个:

@Output() bannerChanged = new EventEmitter<void>();
...
changeBanner(){
   this.bannerChanged.emit();
}

changeBanner 函数将在您按下按钮时被调用

如果你不想要那个,那么创建一个名为 'settings' 的 SettingsReducer 并订阅它的更改,当在 SettingsComponent 中按下按钮时调度更改:

//in app.module.ts
StoreModule.forRoot({settings: SettingsReducer})
//in SettingsReducer
export function SettignsReducer(state: SettingStore = SettingsState, { type, payload}){
   switch (type) {
      case ('SETTINGS_CHANGED'):
         return (Object.assign({}, state, { settingValue: payload });
   }
}

//in appComponent
constructor(private store: Store<SettingStore>){
   this.store.select('settings').subscribe(value => this.changeBanner = value['settingValue'];);
}

//in SettingsComponent
buttonClicked(){
   let value = !this.currentValue;
   this.store.dispatch({type: 'SETTINGS_CHANGED', payload: value});
}