Я думаю, что лучшим решением для ваших требований является использование 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>