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

旧街凉风 提交于 2019-12-21 17:22:33

问题


It seems there is no way to watch changes in the parent component when using two-way data binding.

I have a custom input component for collecting a tag list. Two-way data binding is setup and working between this component and its parent.

// 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>

In the parent component how do you watch the bound variable for changes? While it's always up to date (I've confirmed this) I cannot find any guidance on reacting to changes.

I've tried:

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

and

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

UPDATE: TWDB IMHO is not what it is advertised to be. Whenever I arrive at this place where TWDB seems to be a solution I rearchitect for a service and or observable communication instead.


回答1:


When you implement a two way binding of your own, you have to implement an event Emitter. The syntax for that is mandatory.

this means that you have a hook to listen to if the value changes.

Here is a demo :

<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

From what I know, this seems the less annoying way to use it, and any two way binding will follow the same rule no matter what, i.e. it ends with the Change word !




回答2:


Your implementation is actually not two-way databinding, the parent and child component are just sharing a reference on the same skillTags variable.

The syntax [(tags)]='skillTags' is syntaxic sugar for [tags]='skillTags' (tagsChange)='skillTags = $event'

You need to implement tagsChange in the child component like this: @Output('tagsChange') tagsChange = new EventEmitter<any>();, then any time you want to modify tags into the children component, dont do it directly, but use this.tagsChange.emit(newValue) instead.

At this point, you'll have real two-way databinding and the parent component is the unique owner of the variable (responsible for applying changes on it and broadcasting changes to the children).

Now in your parent component, if you want to do more than skillTags = $event (implicitly done with [(tags)]='skillTags'), then just add another listener with (tagsChange)='someFunction($event)'.

StackBlitz Demo




回答3:


Don't know if this is what you're looking for, but have you tried using @Input()?

In child component

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

In parent component

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

The input function is called every time the object binded to the function is changed.




回答4:


1.you can use output(eventemitter)

2.easiest solution is rxjs/subject. it can be observer and observable in same time

Usage:

1.Create Subject Property in service:

import { Subject } from 'rxjs';

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

2.When event happend in child page/component use :

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

3.And subscribe to subject in parent page/component:

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

Update

for two-way binding you can use viewchild to access to your child component items and properties

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

and in ts file

  @ViewChild('test') inputTagsComponent : InputTagsComponent;

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



回答5:


you could listen to the change:

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

or use getter and setter:

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

another approach:

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


来源:https://stackoverflow.com/questions/56154917/angular-two-way-data-binding-and-watching-for-changes-in-parent-component

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!