Ok so far I was successfully able to bind <paper-radio>
, <paper-checkbox>
with ngModel by using a Custom ControlValueAccessor
for each one of them. Now I'm stuck at <paper-dropdown-menu>
Here the scenario, I can capture the paper-dropdown (iron-select) but cannot bind -two-way, i.e., using ngModel below is the HTML and custom accessor class
My 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>
And My Custom Accessor Class
/**
* 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));
}
}
Full working example. I didn't find a proper way to apply the
ControlValueAccessor
to<paper-dropdown-menu>
but instead added it to the embeeded<paper-listbox>
. The only disadvantage is that you might need a differentControlValueAccessor
if you use a different content for<paper-dropdown-menu>
, the advantage is that you can use theControlValueAccessor
with<paper-listbox>
even when it's not wrapped in a<paper-dropdown-menu>
Plunker example
Update
I found a similar answer for
PaperDropdownMenu
instead ofPaperListbox
Bind angular 2 model to polymer dropdown