Angular双向数据绑定和监听父组件的变化

Angular Two-Way Data Binding and Watching for Changes in Parent Component

使用双向数据绑定时,似乎无法查看父组件的变化。

我有一个用于收集标签列表的自定义输入组件。双向数据绑定已设置并在此组件与其父组件之间工作。

// the parent component is just a form
// here is how I'm adding the child component
<input-tags formControlName="skillField" [(tags)]='skillTags' (ngModelChange)="skillTagUpdate($event)">
</input-tags>

在父组件中如何观察绑定变量的变化?虽然它始终是最新的(我已经确认了这一点),但我找不到任何关于对变化做出反应的指导。

我试过:

ngOnChanges(changes: SimpleChanges) {
    if (changes['skillTags']) {
        console.log(this.skillTags);  // nothing
    }
}

skillTagUpdate(event){
    console.log(event); // nothing
}

更新: TWDB 恕我直言,并不是它所宣传的那样。每当我到达这个 TWDB 似乎是解决方案的地方时,我都会重新设计服务和/或可观察通信。

你可以听到变化:

<input-tags formControlName="skillField" [tags]='skillTags' (tagsChange)='skillTags=$event; skillTagUpdate();'></input-tags>

或使用getter和setter:

get skillTags(): string {
    return ...
}
set skillTags(value) {
    variable = value;
}

另一种方法:

 export class Test implements DoCheck {
  differ: KeyValueDiffer<string, any>;
  public skillTags: string[] = [];
  ngDoCheck() {
    const change = this.differ.diff(this.skillTags);
    if (change) {
      change.forEachChangedItem(item => {
        doSomething();
      });
    }
  }
  constructor(private differs: KeyValueDiffers) {
    this.differ = this.differs.find({}).create();
  }
}}

1.you 可以使用输出(eventemitter)

2.easiest 解是rxjs/subject。它可以同时被观察者和可观察者

用法:

1.Create 服役对象 属性:

import { Subject } from 'rxjs';

export class AuthService {
   loginAccures: Subject<boolean> = new Subject<boolean>();
}

2.When 事件发生在 child page/component 使用:

logout(){
  this.authService.loginAccures.next(false);
}

3.And 订阅 parent 中的主题 page/component:

constructor(private authService: AuthService) {
    this.authService.loginAccures.subscribe((isLoggedIn: boolean) => {this.isLoggedIn = isLoggedIn;})
}

更新

对于 two-way 绑定,您可以使用视图child 访问您的 child 组件项目和属性

<input-tags #test></<input-tags>

并在 ts 文件中

  @ViewChild('test') inputTagsComponent : InputTagsComponent;

save()
{
   var childModel = this.inputTagsComponent.Model;
}

不知道这是否是您要找的,但您是否尝试过使用@Input()?

在子组件中

@Input() set variableName(value: valueType) {
  console.log(value);
}

在父组件中

<input-tags formControlName="skillField" [(tags)]='skillTags'
[variableName]="skillTagUpdate($event)"></input-tags>

每次更改绑定到函数的对象时都会调用输入函数。

当您实现自己的双向绑定时,您必须实现一个事件发射器。语法是强制性的。

这意味着如果值发生变化,您有一个钩子可以监听。

这是一个演示:

<hello [(name)]="name" (nameChange)="doSomething()"></hello>
_name: string;
@Output() nameChange = new EventEmitter();

set name(val) {
  this._name = val;
  this.nameChange.emit(this._name);
}

@Input()
get name() {
  return this._name;
}

counter = 0;

ngOnInit() {
  setInterval(() => {
    this.name = this.name + ', ' + this.counter++;
  }, 1000);
}

Stackblitz

据我所知,这似乎是一种不那么烦人的使用方式,无论如何任何双向绑定都将遵循相同的规则,即它以 Change 字结尾!

您的实现实际上不是 two-way 数据绑定,父组件和子组件只是共享对同一个 skillTags 变量的引用。

语法 [(tags)]='skillTags'[tags]='skillTags' (tagsChange)='skillTags = $event'

的语法糖

你需要在子组件中实现tagsChange这样:@Output('tagsChange') tagsChange = new EventEmitter<any>();,那么任何时候你想在子组件中修改tags,不要直接这样做,但是请改用 this.tagsChange.emit(newValue)

此时,您将拥有真正的 two-way 数据绑定,并且父组件是变量的唯一所有者(负责在其上应用更改并将更改广播给子组件)。

现在在你的父组件中,如果你想做的不仅仅是skillTags = $event(用[(tags)]='skillTags'隐式完成),那么只需添加另一个监听器(tagsChange)='someFunction($event)'

StackBlitz Demo