13

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

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

// 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 似乎是一种解决方案的地方时,我都会为服务和/或可观察的通信重新架构。

4

5 回答 5

14

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

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

这是一个演示:

<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);
}

堆栈闪电战

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

于 2019-06-21T14:49:37.463 回答
3

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

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

您需要tagsChange像这样在子组件中实现:@Output('tagsChange') tagsChange = new EventEmitter<any>();,然后任何时候要修改tags到子组件中,不要直接这样做,而是使用this.tagsChange.emit(newValue)

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

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

StackBlitz 演示

于 2019-06-21T16:56:38.300 回答
1

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

在子组件中

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

在父组件中

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

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

于 2019-06-18T14:58:24.043 回答
-1

你可以听听变化:

<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();
  }
}}
于 2019-05-15T17:55:09.913 回答
-1

1.你可以使用输出(事件发射器)

2.最简单的解决方案是 rxjs/subject。它可以同时是观察者和可观察的

用法:

1.在服务中创建主题属性:

import { Subject } from 'rxjs';

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

2.当事件发生在子页面/组件使用时:

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

3.并订阅父页面/组件中的主题:

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

更新

对于双向绑定,您可以使用 viewchild 访问您的子组件项和属性

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

并在 ts 文件中

  @ViewChild('test') inputTagsComponent : InputTagsComponent;

save()
{
   var childModel = this.inputTagsComponent.Model;
}
于 2019-06-18T13:15:53.927 回答