If you want to create a unique custom form control, consider implementing a custom directive with an HTML structure like this:
<select-component [(ngModel)]="value">
<div select value="1">One</div>
<div select>Two</div>
</select-component>
To achieve this, we will create a directive with the selector [select]
:
@Directive({
selector: '[select]',
})
export class SelectDirective implements AfterViewInit {
@Input('value') value:any;
control:any;
@HostBinding('class.selected')
get isSelected(){
return this.control && this.control.value == this.value ? true : undefined;
}
@HostBinding('class.select') setClass() { return true; }
@HostListener('click') onclick() {
console.log(this.value);
if (this.control)
this.control.setValue(this.value);
}
constructor(private el: ElementRef) {}
ngAfterViewInit() {
this.value = this.value || this.el.nativeElement.innerHTML;
}
}
In this code snippet, we assign a value to this.value
in ngAfterViewInit
if it is not previously defined. We also have two class bindings for styling purposes: one for the component and another when the div is selected.
The SelectComponent
acts as a custom form control. In ngAfterViewInit
, we link the directives inside it to communicate with the component:
@Component({
selector: 'select-component',
template: `<ng-content></ng-content>`,
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => SelectComponent),
multi: true
}
]
})
export class SelectComponent implements ControlValueAccessor, AfterViewInit {
@ContentChildren(SelectDirective) selects: QueryList<SelectDirective>;
value: any;
disabled: boolean = false;
onChange: any;
onTouched: any;
writeValue(value: any[] | any): void {
this.value = value;
}
registerOnChange(fn: any): void {
this.onChange = fn;
}
registerOnTouched(fn: any): void {
this.onTouched = fn;
}
setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled;
}
ngAfterViewInit() {
this.selects.forEach(x => {
x.control = this;
});
}
setValue(value) {
this.value = value;
this.onChange(value);
}
}
Check out the complete implementation on StackBlitz.