【问题标题】:Angular2 bind value to structural directiveAngular2将值绑定到结构指令
【发布时间】:2019-05-30 21:04:53
【问题描述】:

所以我一直在尝试为输入创建自己的自定义下拉菜单,因此我创建了一个结构指令来在我想要使用它的输入元素下创建一个下拉列表。最好我想在我使用指令的组件中绑定一个值,这样我就可以更新表单控件,而不必直接访问 DOM。

我觉得应该有一种简单直接的方法来做到这一点,我很可能会错过。 * 装饰器似乎消除了从指令中创建输出的可能性,并且还与 Elementref 混淆,因为它将元素变成了嵌入的模板。

非常欢迎任何帮助,我已经尝试解决了一段时间,但似乎找不到答案。

Plunkr:https://embed.plnkr.co/OPxSY7PKTCo1sDpksF8j/

【问题讨论】:

    标签: angular angular2-directives


    【解决方案1】:

    我认为满足您要求的最佳解决方案是使用ControlValueAccessor。使用这种方法,您无需搞砸使用创建组件的指令等等(正如我们从您的演示中看到的那样)。通过这种方式,您可以创建一个组件来完成您需要的所有工作。

    Angular 文档说:

    ControlValueAccessor 在 Angular FormControl 实例和原生 DOM 元素之间建立了一座桥梁。

    这是带有您的 plunker 代码的 ControlValueAccessor 的工作 StackBlitz demo

    这就是您实现ControlValueAccessor 下拉菜单的方式:

    dropdown.component.ts

    import { Component, HostListener, EventEmitter, ElementRef, forwardRef } from '@angular/core';
    import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
    
    const noop = () => { };
    
    const CUSTOM_INPUT_CONTROL_VALUE_ACCESSOR: any = {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => DropdownComponent),
      multi: true
    };
    
    @Component({
      selector: 'appDropdown',
      templateUrl: './dropdown.component.html',
      providers: [CUSTOM_INPUT_CONTROL_VALUE_ACCESSOR]
    })
    export class DropdownComponent implements ControlValueAccessor {
      private _value = false;
      private isDisabled = false;
      private onTouched: () => void = noop;
      private onChange: (value: any) => void = noop;
    
      get value() {
        return this._value;
      }
    
      isShowDropdown = false;
    
      public clickedOutside: EventEmitter<void> = new EventEmitter<void>();
      rows = [{ name: 'One', value: 1 }, { name: 'Two', value: 2 }, { name: 'Three', value: 3 }];
    
      constructor(private elementRef: ElementRef) { }
    
      @HostListener('document:click', ['$event.target'])
      public onDocumentClick(targetElement) {
        if (!this.elementRef.nativeElement.contains(targetElement)) {
          this.isShowDropdown = false;
        }
      }
    
      onRowSelected(value: any) {
        this.onTouched();
        if (!this.isDisabled) {
          this.writeValue(value);
        }
        this.isShowDropdown = false;
      }
    
      //#region ControlValueAccessor implement
    
      writeValue(value: any): void {
        console.log(value);
        this._value = value;
        this.onChange(value);
      }
      registerOnChange(fn: any): void {
        this.onChange = fn;
      }
      registerOnTouched(fn: any): void {
        this.onTouched = fn;
      }
      setDisabledState?(isDisabled: boolean): void {
        this.isDisabled = isDisabled;
      }
    
      //#endregion ControlValueAccessor implement
    }
    

    dropdown.component.html

    <input [value]="value">
    <div *ngIf="isShowDropdown" style="position: absolute">
        <h4 style="border: 1px solid grey; padding: 5px; margin: 0px" *ngFor="let row of rows" (click)="onRowSelected(row.name)">
            {{ row.name }}
        </h4>
    </div>
    <button (click)="isShowDropdown = !isShowDropdown;">*</button>
    

    最后,在 app.component.html 中使用它:

    <appDropdown #inp="ngModel" name="inp" [(ngModel)]="startValue"></appDropdown>
    

    【讨论】:

    • 很好的答案,不知道这存在。非常感谢!
    猜你喜欢
    • 1970-01-01
    • 2016-11-02
    • 2017-12-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-30
    • 2020-04-21
    相关资源
    最近更新 更多