本文介绍了ngModel绑定到聚合物下拉列表(Angular2)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

好的,到目前为止,我通过对每一个使用自定义ControlValueAccessor,成功地将<paper-radio><paper-checkbox>与ngModel绑定了.现在我被困在<paper-dropdown-menu>在这种情况下,我可以捕获纸张下拉菜单(iron-select),但是不能绑定双向,即使用下面的ngModel是HTML和自定义访问器类

我的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));
    }
}
解决方案

完整的示例.我没有找到将ControlValueAccessor应用于<paper-dropdown-menu>的正确方法,而是将其添加到了嵌入的<paper-listbox>中.唯一的缺点是,如果对<paper-dropdown-menu>使用不同的内容,则可能需要使用不同的ControlValueAccessor.优点是,即使ControlValueAccessor没有包装在<paper-dropdown-menu> ControlValueAccessor与<paper-listbox>一起使用. /p>

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;
  }
}

> 柱塞示例

更新

我为PaperDropdownMenu而不是PaperListbox找到了类似的答案绑定聚合物下拉的角度2模型

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 different ControlValueAccessor if you use a different content for <paper-dropdown-menu>, the advantage is that you can use the ControlValueAccessor with <paper-listbox> even when it's not wrapped in a <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

Update

I found a similar answer for PaperDropdownMenu instead of PaperListbox Bind angular 2 model to polymer dropdown

这篇关于ngModel绑定到聚合物下拉列表(Angular2)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-21 20:29