WeekendMan
WeekendMan

Reputation: 621

Angular 5 setter over the @Input doesn't work

I have a project based on the Angular 5. Lets say that I have the two components: ParentComponent and ChildComponent. ChildComponent has public setter with @Input() decorator. I give to it property from the parent component that will be changed later.

My problem is - this setter doesn't work with Maps, Interfaces, Objects like

{ [ key: string ]: boolean }

only with Arrays and primitives.

Well, it works, but only once.

I already understand that it's something with the data type but who can give a good explanation or link to the docs? Didn't find the allowed data types on the Angular web-site with docs.

What's wrong here?

Link to plunker if someone needs: https://plnkr.co/edit/WBS55F3wZSYI0qGNEGSd?p=preview

As you can see, there are 3 setters, they work in the first time, then only Array and String setters work. Why?

Update: Looks like it works if I change in the Map some value by its key that already exists, but doesn't work if I add new key=>value pair.

Upvotes: 1

Views: 1203

Answers (1)

Igor
Igor

Reputation: 62213

The fields mapItemsData and arrayItemsData are both only set one time. The field stringItemData is set each time the object reference changes and this is because it is a string type and strings are immutable. The line this.stringItem += this.iterationValue.toString(); actually creates a new string reference each time it is called which causes the child component's setter to be called again with the new value.


The reason you do not see the data being updated for mapItemsData is because you can't iterate it using *ngFor but if you add this to your template you can see that the same object is updated

{{mapItems.size}}

If you wanted to iterate the Map collection you can do that using entries().

<div *ngFor="let item of mapItems.entries()">{{ item }}</div>

For more information on the type Map see the documentation.


You also need to change your setting code so you do not point to a different (new) instance but point to the same instance that is being referenced in your parent (containing) component.

public set mapItemsData(set: Map<string, boolean>) {
    // this.mapItems = []; <- you were changing the reference here
    this.mapItems = set; // this is really all you need
}

Updated plunker

Upvotes: 2

Related Questions