How i can use two-way binding on Map objects?
The following code doesn't work as expected:
Component:
@Component({
moduleId: module.id,
selector: "my-component",
templateUrl: "my-component.html",
styleUrls: ["my-component.scss"],
})
export class MyComponent {
myMap: Map<string, Object> = Map<string, Object>()
.set('first', {text: 'abc'})
.set('second', {text: 'foo'})
;
}
Template:
<div class="items" *ngFor="let item of myMap.values()">
<input type="text" [(ngModel)]="item.text" />
</div>
Angular v2+ supports two-way data binding using ngModel directive and also by having getter and setter methods.
Two-way binding gives components in your application a way to share data. Use two-way binding to listen for events and update values simultaneously between parent and child components.
The answer is "no". In your example, the value that you pass to the @Input property is a reference to an object. If you had two-way binding, you could assign a new object to that property in the child component: and the corresponding property in the parent component would be updated accordingly.
Two-way data binding can be achieved using a ngModel directive in Angular. The below syntax shows the data binding using (ngModel), which is basically the combination of both the square brackets of property binding and parentheses of the event binding.
Actually in this example two-way data binding works as expected. Probably your mistake is in creating Map object:
myMap: Map<string, Object> = Map<string, Object>()
You have to include new
keyword before Map
(because Map Constructor is not callable):
myMap: Map<string, Object> = new Map<string, Object>()
.set('first', {text: 'abc'})
.set('second', {text: 'foo'})
And now everything works as expected. You can check this stackblitz demo as well.
Notice: According to this Angular issue on GitHub: Maps have no orders in keys and hence they iteration is unpredictable. This was supported in ng1, but we think it was a mistake and will not be supported in NG2.
One of the simplest solutions for this - is to use Array.from()
method on myMap.entries()
:
getEntities() {
// this will return [['first', { text: 'abc' }], ... ]
// and after mapping we get [{ text: 'abc' }, ...]
return Array.from(this.myMap.entries()).map(item => item[1]);
}
And now we can use it in the template:
<div class="items" *ngFor="let item of getEntities()">
<input type="text" [(ngModel)]="item.text" />
</div>
In this example two-way data-binding works as well.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With