Значение привязки Angular2 к структурной директиве - PullRequest
0 голосов
/ 04 января 2019

Итак, я пытался создать свое собственное выпадающее меню для ввода, и поэтому я создал структурную директиву для создания выпадающего списка под элементом ввода, для которого я хочу его использовать.Предпочтительно я хочу привязать значение в компоненте, для которого я использую директиву, чтобы я мог обновить элемент управления формы, и мне не нужно обращаться к DOM напрямую.

Мне кажется, что должно быть легкои прямой способ сделать это, что мне, скорее всего, не хватает.Декоратор *, кажется, удаляет возможность создания Output из директивы, а также портит Elementref, поскольку он превращает элемент во встроенный шаблон.

Любая помощь очень приветствуется, я пытался решить эту проблемукакое-то время и не могу найти ответ.

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

1 Ответ

0 голосов
/ 09 января 2019

Я думаю, что лучшим решением для ваших требований является использование ControlValueAccessor . При таком подходе вам не нужно возиться с использованием директивы, которая создает компонент и т. Д. (Как мы видим из вашей демонстрации). Таким образом, вы можете создать компонент, который будет выполнять всю необходимую работу.

В угловых документах сказано:

ControlValueAccessor создает мост между экземплярами Angular FormControl и собственными элементами DOM.

Вот рабочая StackBlitz демонстрация ControlValueAccessor с вашим кодом плунжера.

Вот как вы реализуете раскрывающийся список 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>
...