Bind angular 2 model to polymer dropdown
Asked Answered
C

1

5

I decided to take some time this weekend to look at Angular 2 and Polymer. I'm really interested in angular 2 and would really like to start building something with it. One downside with starting with Angular 2 now is that there is no good component library yet. However, since Angular 2 claims that it should work so good together with Web Components I thought of giving Polymer a try. I have succeeded to bind data to simple components like an input field. What I'm stuck at for the moment is how to bind a model to the selected object of a paper-dropdown-menu. Since I'm very new into both I don't really know how to do it but this is what I have tried so far. Has anyone accomplished to bind an angular 2 model to a polymer dropdown?

<paper-dropdown-menu  >
   <paper-menu class="dropdown-content" valueattr="id" [(ng-model)]="model">
       <paper-item *ng-for="#m of options" id="{{m.id}}" (click)="onClick()">{{m.name}}</paper-item>
   </paper-menu>
</paper-dropdown-menu>

EDIT: I have now created a ValueAccessor which seems to work acceptable with one exception. I try to get the dropdown to have a pre-selected value by setting the selected attribute in the writeValue method. At first this seemed to work but after I made this change I can no longer change the selected value. It works if I hardcode the value in the template so it seems to have something to do with angular together with polymer. I tried to follow the stacktrace and compare the difference between the two are. When I hardcode the value a setter method for selected is executed which trigger an item-select event. When I follow the same trace when I set the property in the valueAccessor there the setter method is no longer executed. Seems to be a problem with the interaction between angular 2 and polymer.

import {Directive, ControlValueAccessor, ElementRef, Renderer, NG_VALUE_ACCESSOR, Provider, forwardRef} from "angular2/angular2"
import {isBlank, CONST_EXPR} from 'angular2/src/facade/lang';
import {setProperty} from "angular2/src/common/forms/directives/shared"

const PAPER_DROPDOWN_VALUE_ACCESSOR = CONST_EXPR(new Provider(
    NG_VALUE_ACCESSOR, {useExisting: forwardRef(() => PaperDrowpdownMenuAccessor), multi: true}));

@Directive({
  selector: 'paper-menu[ng-model]',
  bindings: [PAPER_DROPDOWN_VALUE_ACCESSOR]
})
export class PaperDrowpdownMenuAccessor implements ControlValueAccessor {

  onChange = (_) => {};
  onTouched = () => {};

  constructor(private _renderer: Renderer, private _elementRef: ElementRef) {
    var self = this;
    this._elementRef.nativeElement.addEventListener('iron-select', function(e, v, s){
      console.log(e.target.selected);
      self.onChange(e.target.selected);
    });
  }

  writeValue(value: any): void {
    if(value){
      if(this._elementRef.nativeElement.select) {
        this._elementRef.nativeElement.select(value);
      }
      else {
        //this._elementRef.nativeElement.attributes["selected"]
        setProperty(this._renderer, this._elementRef, 'selected', value);
      }
    }       
  }

  registerOnChange(fn: () => any): void { 
    this.onChange = fn; 
  }
  registerOnTouched(fn: () => any): void { this.onTouched = fn; }
}
Cnemis answered 29/11, 2015 at 9:28 Comment(2)
PrimeNG's dropdown can bind to model implicitly. primefaces.org/primeng/#/dropdownReisinger
Similar answer for use of PaperDropdownMenu with PaperListbox #37203043Tappet
C
3

I finally solved this by my own by implementing a custom Value Accessor, mainly by looking at how the default value accesssor is implmented. https://github.com/angular/angular/blob/2.0.0-alpha.46/modules/angular2/src/common/forms/directives/default_value_accessor.ts

I struggled a bit with this since paper-menu wants the pre-selected value to be set as an attribute in the rendered html. In my first attempt I used angulars internal setProperty to set the selected value. However, this sets the DOM property and not the HTML attribute and resulted in that polymer didn't create a get,set property of selected which prevented the menu to trigger iron-select event which the dropdown menu listens for. Lesson learned, remember the difference between HTML and DOM.

import {Directive, ControlValueAccessor, ElementRef, Renderer, NG_VALUE_ACCESSOR, Provider, forwardRef} from "angular2/angular2"
import {CONST_EXPR} from 'angular2/src/facade/lang';

const PAPER_MENU_VALUE_ACCESSOR = CONST_EXPR(new Provider(
    NG_VALUE_ACCESSOR, {useExisting: forwardRef(() => PaperMenuAccessor), multi: true}));

@Directive({
  selector: 'paper-menu[ng-model]',
  bindings: [PAPER_MENU_VALUE_ACCESSOR]
})
export class PaperMenuAccessor implements ControlValueAccessor {

  onChange = (_) => {};
  onTouched = () => {};

  constructor(private _renderer: Renderer, private _elementRef: ElementRef) {
    this._elementRef.nativeElement.addEventListener('iron-select', (e) => {
      this.onChange(e.target.selected);
    });
  }

  writeValue(value: any): void {
    if(this._elementRef.nativeElement.select) {
      this._elementRef.nativeElement.select(value);
    }
    else {
      this._elementRef.nativeElement.setAttribute("selected", value);
    }   
  }

  registerOnChange(fn: () => any): void { this.onChange = fn; }
  registerOnTouched(fn: () => any): void { this.onTouched = fn; }
}
Cnemis answered 29/11, 2015 at 18:18 Comment(3)
I am fairly new with Angular2 and am working to try and get it and Polymer 1 to play nicely together in the same app..Currently using beta 6. They seem to work well together so far, some of the quirky things can be resolved by fully enabling shadow dom for Polymer, at least I have found. Is this sort of a hacky fix/workaround though? Should I be looking more into deeper Angular2 things for compatibility or have you found it doesn't take too much workaround to get them to work well?Tervalent
I'm not sure how the latest version of Angular 2 and Polymer works together but from you comment it sounds like it might be a bit better now compared to when I tried it. I abandoned my attempt to get them to work together because I had to do too much workarounds. My hope was to be able to use third-party polymer elements too but when I tried some components I found that the work to get them to play nicely together was to big for me so I reverted back to angular/material and am currently waiting for angular 2 material.Cnemis
yeah its getting better but far from perfect. ThanksTervalent

© 2022 - 2024 — McMap. All rights reserved.