2016-05-13 38 views
1

好吧,到目前爲止,我成功地能夠綁定<paper-radio>,<paper-checkbox> ngModel通過使用自定義ControlValueAccessor爲他們每個人。現在我被困在<paper-dropdown-menu> 這裏的情況,我可以捕捉紙張下拉(鐵選),但不能綁定 - 雙向的,即,使用如下ngModel是HTML和自定義訪問類ngModel綁定聚合物下拉列表(Angular2)

我form.html

<paper-dropdown-menu [(ngModel)]="mymodel.selection" label="Your Fix"> 
      <paper-menu class="dropdown-content"> 
       <paper-item value="1" ngDefaultControl>Coffee</paper-item> 
       <paper-item value="2" ngDefaultControl>Cigarettes</paper-item> 
       <paper-item value="3" ngDefaultControl>Chivas</paper-item></paper-menu> 
</paper-dropdown-menu> 

而我的自定義訪問器類

/** 
* Created by pratik on 12/5/16. 
*/ 
import { 
    Query, 
    Directive, 
    Renderer, 
    Self, 
    forwardRef, 
    Provider, 
    ElementRef, 
    QueryList 
} from 'angular2/core'; 

import {ObservableWrapper} from 'angular2/src/facade/async'; 
import {NG_VALUE_ACCESSOR, ControlValueAccessor} from 'angular2/common'; 
import {CONST_EXPR} from 'angular2/src/facade/lang'; 

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

/** 
* Marks `<option>` as dynamic, so Angular can be notified when options change. 
* 
* ### Example 
* 
* ``` 
* <select ngControl="city"> 
* <option *ngFor="#c of cities" [value]="c"></option> Need to change to paper-item 
* </select> 
* ``` 
*/ 
@Directive({selector: 'option'}) // Tried changing to paper-item but still doesn't work 
export class NgSelectOption { 
} 

/** 
* The accessor for writing a value and listening to changes on a select element. 
*/ 
@Directive({ 
    selector: 'paper-dropdown-menu[ngControl],paper-dropdown-menu[ngFormControl],paper-dropdown-menu[ngModel]', 
    host: { 
     '(iron-select)': 'onChange($event.target.value)',   
     '(input)': 'onChange($event.target.value)', 
     '(blur)': 'onTouched()' 
    }, 
    bindings: [SELECT_VALUE_ACCESSOR] 
}) 
export class SelectControlValueAccessor implements ControlValueAccessor { 
    value: string; 
    onChange = (_) => {}; 
    onTouched =() => {}; 


    constructor(private _renderer: Renderer, private _elementRef: ElementRef, 
       @Query(NgSelectOption, {descendants: true}) query: QueryList<NgSelectOption>) { 
     this._updateValueWhenListOfOptionsChanges(query); 
    } 

    writeValue(value: any): void { 
     this.value = value; 
     this._renderer.setElementProperty(this._elementRef, 'value', value); 
    } 

    registerOnChange(fn:() => any): void { this.onChange = fn; } 
    registerOnTouched(fn:() => any): void { this.onTouched = fn; } 

    private _updateValueWhenListOfOptionsChanges(query: QueryList<NgSelectOption>) { 
     ObservableWrapper.subscribe(query.changes, (_) => this.writeValue(this.value)); 
    } 
} 

回答

1

全部工作的例子。我沒有找到合適的方法將ControlValueAccessor應用到<paper-dropdown-menu>,而是將其添加到嵌入的<paper-listbox>。唯一的缺點是,如果你使用一個不同的內容爲<paper-dropdown-menu>你可能需要一個不同的ControlValueAccessor的好處是,你可以使用ControlValueAccessor<paper-listbox>即使它不是包裹在一個<paper-dropdown-menu>

import { 
    Component, 
    Directive, 
    Renderer, 
    forwardRef, 
    Provider, 
    ElementRef, 
    ViewEncapsulation, 
} from '@angular/core'; 

import {NG_VALUE_ACCESSOR, ControlValueAccessor} from '@angular/common'; 
const PAPER_MENU_VALUE_ACCESSOR = new Provider(
    NG_VALUE_ACCESSOR, {useExisting: forwardRef(() => PaperMenuControlValueAccessor), multi: true}); 


@Directive({ 
    selector: 'paper-listbox', 
    host: {'(iron-activate)': 'onChange($event.detail.selected)'}, 
    providers: [PAPER_MENU_VALUE_ACCESSOR] 

}) 
export class PaperMenuControlValueAccessor implements ControlValueAccessor { 
    onChange = (_:any) => { 
    }; 
    onTouched =() => { 
    }; 

    constructor(private _renderer:Renderer, private _elementRef:ElementRef) { 
    console.log('PaperMenuControlValueAccessor'); 
    } 

    writeValue(value:any):void { 
    //console.log('writeValue', value); 
    this._renderer.setElementProperty(this._elementRef.nativeElement, 'selected', value); 
    } 

    registerOnChange(fn:(_:any) => {}):void { 
    this.onChange = fn; 
    } 

    registerOnTouched(fn:() => {}):void { 
    this.onTouched = fn; 
    } 
} 
@Component({ 
    selector: 'my-app', 
    directives: [PaperMenuControlValueAccessor], 
    encapsulation: ViewEncapsulation.None, 
    template: ` 
<h2>Hello {{name}}</h2> 

<paper-menu> 
    <paper-item>Item 1</paper-item> 
    <paper-item>Item 2</paper-item> 
</paper-menu> 


<paper-dropdown-menu label="Dinosaurs" > 
    <paper-listbox class="dropdown-content" [(ngModel)]="selected"> 
    <paper-item *ngFor="let item of items">{{item}}</paper-item> 
    </paper-listbox> 
</paper-dropdown-menu> 

<div>selected: {{items[selected]}}</div>  
    `, 
}) 
export class AppComponent { 
    items = ['allosaurus', 'brontosaurus', 'carcharodontosaurus', 'diplodocus']; 
    selected = 3; 
    name:string; 

    constructor() { 
    this.name = 'Angular2 (Release Candidate!)' 
    } 

    ngAfterViewInit() { 
    //this.selected = this.diplodocus; 
    } 
} 

Plunker example

更新

我發現了一個類似的答案,而不是PaperDropdownMenuPaperListboxBind angular 2 model to polymer dropdown

+0

IM好奇,如果'ngModel'會工作結合上''而不是'<紙下拉菜單>'模型,尋找進入它.. –

+1

!! ...只是真棒@zoechi!我一直在嘗試一段時間,非常感謝!你的plunker例子的工作原理,我沒有修改導入到beta17,因爲應用程序正在使用路由。我主要關注的是要檢查使用Polymer和Angular2是否明智,因爲我聽說它將成爲事實上的未來。不管怎樣,再次感謝! –

+0

有幾個問題。當您需要將模板元素傳遞給Polymer元素或有時需要使用定製Polymer元素來包裝paper-xxx元素時。但總體而言,它應該可以正常工作。 –