Nick
Nick

Reputation: 41

Using Angular 2 two-way data binding with Polymer

I'm trying to combine Polymer elements with Angular 2 and I struggle with the two-way data binding aspect.

As an example I use paper-tabs and display the tab number that is currently in use. Whenever I change a tab, I want that change to happen in a tabNr field in the AppComponent as well. Whenever I click on the tab number that is being displayed, I want the number to change and change the tab accordingly. My initial approach was this:

import {Component} from 'angular2/core';

@Component({
    selector: 'my-app',
    template: `
                <paper-toolbar>
                    <paper-tabs [(selected)]="tabNr">
                        <paper-tab>Tab 1</paper-tab>
                        <paper-tab>Tab 2</paper-tab>
                        <paper-tab>Tab 3</paper-tab>
                    </paper-tabs>
                </paper-toolbar>
                <paper-toolbar>
                    <div (click)="traverse()">Tab {{tabNr + 1}}</div>
                </paper-toolbar>
                `
})
export class AppComponent {
    tabNr = 0;

    traverse() {
        this.tabNr = (this.tabNr + 1) % 3;
    }

}

However, this does not work. I can't change the tabs. I can click the Tab number being displayed to change that, but that is also not reflected in the actual tabs. In the following I'll focus on that line in the code to discuss all other possibilities I tried out:

<paper-tabs [(selected)]="tabNr">

I was expecting that one way data-binding (paper-tabs going to the AppComponent) would work like this

<paper-tabs (selected)="tabNr">

but that doesn't work. To actually get the changes to register, I need to use the event from Polymer like this:

<paper-tabs selected="tabNr" (selected-changed)="tabNr=$event.detail.value">

That defeats the purpose of using Angular 2 for the bindings. It seems to me that the problem here is, that polymer is firing a different event for the change than whatever Angular 2 is expecting.

In order to get the click-changes to register with the tabs I have to do this:

<paper-tabs [attr.selected]="tabNr">

However, I cannot combine both of those result into this

<paper-tabs [attr.selected]="tabNr" (selected-changed)="tabNr=$event.detail.value">

because I get the following exception whenever I change a tab:

EXCEPTION: Expression 'tabNr in AppComponent@2:17' has changed after it was checked. Previous value: '1'. Current value: '1' in [tabNr in AppComponent@2:17]

I assume there is probably some sort of circular event firing going on. I can solve this by using a method for the (selected-changed) event that only changes it if the number of the event is actually a different number, but that whole approach seems cumbersome and I derived quite a bit from simply using [()] to bind the data.

So my question is: Is there a better, cleaner way to do this?

Upvotes: 4

Views: 916

Answers (1)

G&#252;nter Z&#246;chbauer
G&#252;nter Z&#246;chbauer

Reputation: 657248

The right way to for two-way binding is

<paper-tabs [attr.selected]="tabNr" (selected-changed)="updateTab($event)">

or

<paper-tabs attr.selected="{{tabNr}}" (selected-changed)="updateTab($event)">

Plunker example

To avoid the "expression has changed since it was last checked" warning I had to parse the event.detail.value to number.

For

<paper-tabs [(selected)]="tabNr">

to work Polymer would need to send a different event selectedChange instead of selected-changed and the event would need to be the value 1 instead of a custom event.

Upvotes: 2

Related Questions