我有一个父组件(CategoryComponent)、一个子组件(videoListComponent)和一个ApiService。

我的大部分工作都很好,即每个组件都可以访问jsonapi,并通过可观测获取相关数据。

目前,视频列表组件只获取所有视频,我想将其过滤为特定类别中的视频,我通过@Input()将categoryId传递给孩子来实现这一点。

类别组件.html

<video-list *ngIf="category" [categoryId]="category.id"></video-list>

这是有效的,当父CategoryComponent类别发生更改时,categoryId值将通过@Input()传递,但我需要在VideoListComponent中检测到这一点,并通过APIService(使用新的categoryId)重新请求视频数组。

在AngularJS中,我会对变量进行$watch。处理此问题的最佳方法是什么?


当前回答

您也可以将EventEmitter作为输入传递。不太确定这是否是最佳实践,尽管。。。

类别组件:

categoryIdEvent: EventEmitter<string> = new EventEmitter<>();

- OTHER CODE -

setCategoryId(id) {
 this.category.id = id;
 this.categoryIdEvent.emit(this.category.id);
}

类别组件.html:

<video-list *ngIf="category" [categoryId]="categoryIdEvent"></video-list>

在VideoListComponent.ts中:

@Input() categoryIdEvent: EventEmitter<string>
....
ngOnInit() {
 this.categoryIdEvent.subscribe(newID => {
  this.categoryId = newID;
 }
}

其他回答

角度ngOnChanges

ngOnChanges()是一个内置的Angular回调方法,在默认更改检测器检查数据绑定财产(如果至少有一个属性发生了更改)后立即调用。在视图和内容之前,将检查子级。

// child.component.ts

import { Component, OnInit, Input, SimpleChanges, OnChanges } from '@angular/core';

@Component({
  selector: 'app-child',
  templateUrl: './child.component.html',
  styleUrls: ['./child.component.css']
})
export class ChildComponent implements OnInit, OnChanges {

  @Input() inputParentData: any;

  constructor() { }

  ngOnInit(): void {
  }

  ngOnChanges(changes: SimpleChanges): void {
    console.log(changes);
  }

}

更多信息:Angular Docs

如果您正在处理使用@Input在父组件和子组件之间共享数据的情况,则可以使用生命周期方法检测@Input数据更改:ngOnChanges

 ngOnChanges(changes: SimpleChanges) {
    if (!changes.categoryId.firstChange) {
      // only logged upon a change after rendering
      console.log(changes.categoryId.currentValue);
    }
  }

我建议您注意为子组件实施的更改策略,因为某些性能原因,您应该添加ChangeDetectionStrategy.OnPush:

示例代码:

@Component({
  selector: 'app-hero-detail',
  templateUrl: './hero-detail.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class VideoListComponent implements OnChanges {
  @Input() categoryId: string;

此处ngOnChanges将在输入属性更改时始终触发:

ngOnChanges(changes: SimpleChanges): void {
 console.log(changes.categoryId.currentValue)
}

最安全的选择是使用共享服务而不是@Input参数。此外,@Input参数不会检测复杂嵌套对象类型的更改。

一个简单的服务示例如下:

服务.ts

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

@Injectable()
export class SyncService {

    private thread_id = new Subject<number>();
    thread_id$ = this.thread_id.asObservable();

    set_thread_id(thread_id: number) {
        this.thread_id.next(thread_id);
    }

}

组件.ts

export class ConsumerComponent implements OnInit {

  constructor(
    public sync: SyncService
  ) {
     this.sync.thread_id$.subscribe(thread_id => {
          **Process Value Updates Here**
      }
    }
  
  selectChat(thread_id: number) {  <--- How to update values
    this.sync.set_thread_id(thread_id);
  }
}

您可以在其他组件中使用类似的实现,所有组件将共享相同的共享值。

您可以在facade服务中使用BehaviorSubject,然后在任何组件中订阅该主题,当事件发生时触发对其的数据调用.next()的更改。请确保在销毁生命周期挂钩中关闭这些订阅。

data-api.facade.ts

@Injectable({
  providedIn: 'root'
})
export class DataApiFacade {

currentTabIndex: BehaviorSubject<number> = new BehaviorSubject(0);

}

某些组件

constructor(private dataApiFacade: DataApiFacade){}

ngOnInit(): void {
  this.dataApiFacade.currentTabIndex
    .pipe(takeUntil(this.destroy$))
       .subscribe(value => {
          if (value) {
             this.currentTabIndex = value;
          }
    });
}

setTabView(event: MatTabChangeEvent) {
  this.dataApiFacade.currentTabIndex.next(event.index);
}

ngOnDestroy() {
  this.destroy$.next(true);
  this.destroy$.complete();
}