Angular双向数据绑定及在父组件中监测变化

15

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

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

// 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似乎是一个解决方案时,我会重新设计一个服务或可观察的通信。


实际上没有其他相关的内容,它们只是两个非常小的组件。您想查看整个自定义输入(子)组件吗?或者也许是一个 StackBlitz 表示? - Ben Racicot
好的,我已经在SB中添加了一个指向父组件的链接,感谢你帮助我学习这个! - Ben Racicot
你有 StackBlitz 的链接吗? - DavidZ
你尝试过添加 @output 并从输出中发出更改,以便父组件可以处理吗? - paras shah
可能会有一些遗漏,但似乎做出了一个合理的假设,即ngOnChanges将在双向数据绑定更改时被触发。然而,事实并非如此。因此,如果您想要监听双向数据绑定的更改,您需要实现@Output() change: EventEmitter<any> = new EventEmitter()以及双向数据绑定的@Output。这时候就会引出一个问题,自定义双向数据绑定有什么价值呢? - James Parker
显示剩余4条评论
5个回答

18

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

这意味着如果值发生改变,您就可以监听钩子。

以下是一个演示:

<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”结尾!


好的,所以双向绑定实际上只是一个方便的“盒子里的香蕉”,并且与手动绑定相同的设置。因为这就是您设置标准@Output更改的方式。 - Ben Racicot

6

您的实现实际上并不是双向数据绑定,父组件和子组件只是共享同一个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演示版


2

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

在子组件中

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

在父组件中

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

输入函数被称为每次绑定到该函数的对象发生更改时调用。

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

1
是的,我已经尝试过那些,但它们会破坏双向语法设置的目的。 - Ben Racicot
获取器和设置器没有可能的方式吗? - Geggi632
还是这个?<input-tags formControlName="skillField" [(tags)]='skillTags' (tagsChange)='skillTagUpdate();'></input-tags> - Geggi632
我已添加了一个带有设置的StackBlitz。也许这是正确的想法,但它似乎比我最初想象的更加复杂。 - Ben Racicot
添加了另一种方法 - 但这比其他解决方案更复杂。 - Geggi632

-1

1.你可以使用output(eventemitter)。

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

用法:

1.在服务中创建Subject属性:

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

嘿@moha,这个问题涉及到双向数据绑定。 - Ben Racicot
@BenRacicot 这个语句是引用用户的话:“似乎没有办法观察父组件中的变化”。使用 subject 是最好的选择。你还说我的答案不相关吗? - moha noorani
这是一个很好的回答,但我的问题之所以提出来是因为如果你无法在父级中获取值,那么双向数据绑定有什么意义呢?提供一种替代方案固然不错,但与问题无关。(我已经给你点赞了) - Ben Racicot
登录是从哪里来的? - Enrico

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接