I am trying to create a component that implements the ControlValueAccessor. The custom form control will implement a div that will become a ckeditor control that will then used Forms validator but It will not call the ngAfterViewInit on the custom-element and not create the ckeditor control. Should I have the ng-container tag?
view for custom-element
<ng-container *ngIf="controlGroup.controls.value">
<Editor [formControl]="controlGroup.controls.value">
</Editor>
</ng-container>
Component
import { Component, forwardRef, NgZone, EventEmitter, Inject, Input, Output, } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR, FormBuilder, FormGroup, Validators, FormControl } from '@angular/forms';
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
@Component({
selector: 'Editor',
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => Editor),
multi: true
}
],
template: `<div [attr.id]="editorId" contenteditable="true"
style="width: 100% !important; overflow: hidden"
class="form-control sentence-part-values-inline sentence-part-values-inline-textbox-number">
</div>`,
})
export class Editor implements ControlValueAccessor {
@Input() public model: OrderTemplateTool.Core.Sentences.EmeticRisks.RegimenDescriptorSentencePartModel;
getModel(): OrderTemplateTool.Core.Sentences.EmeticRisks.RegimenDescriptorSentencePartModel {
return this.model;
}
editorId: string;
@Output() public modelchange: EventEmitter<any> = new EventEmitter();
public onModelChange(): void {
// this.validate();
this.modelchange.next(this.getModel());
}
constructor(@Inject(NgZone) private ngZone: NgZone) { this.editorId = "regimen-descriptor-" + (<any>window).newGuid(); }
onChange: any = () => { }
onTouch: any = () => { }
val = ""
set value(val) {
if (val !== undefined && this.val !== val) {
this.val = val
this.onChange(val)
this.onTouch(val)
}
}
writeValue(value: any) {
this.value = value
}
registerOnChange(fn: any) {
this.onChange = fn
}
registerOnTouched(fn: any) {
this.onTouch = fn
}
ngAfterViewInit() {
var self = this;
this.ngZone.runOutsideAngular(() => {
console.log('Procssing ngZone');
(<any>window).CKEDITOR.config.autoParagraph = false;
console.log('ngAfterViewInit');
console.log(this.editorId);
if (!(<any>window).CKEDITOR.instances[this.editorId]) {
(<any>window).CKEDITOR.disableAutoInline = true;
(<any>window).CKEDITOR.inline(self.editorId, {
enterMode: 2,
toolbar: [
{
name: 'basicstyles', groups: ['basicstyles', 'cleanup'],
items: ['Bold', 'Italic', 'Underline', 'Strike', 'Subscript', 'Superscript']
},
{
name: 'source',
items: ['Sourcedialog']
}
],
removeButtons: '', //override default value from config.js of CKEDITOR,
extraPlugins: 'sourcedialog'
});
let editor = (<any>window).CKEDITOR.instances[self.editorId];
console.log(editor); (<any>window).CKEDITOR.instances[this.editorId].setData(this.model.Value);
(<any>window).CKEDITOR.instances[this.editorId].on("change", () => {
self.model.Value = (<any>window).CKEDITOR.instances[self.editorId].getData();
var editorName = this.editorId; (<any>window).CKEDITOR.instances[editorName].updateElement();
self.onModelChange();
});
(<any>window).CKEDITOR.instances[this.editorId].on("instanceReady", (ev) => {
var editor = ev.editor;
editor.setReadOnly(false);
});
}
});
}
ngOnDestroy() {
this.ngZone.runOutsideAngular(() => {
var editor = (<any>window).CKEDITOR.instances[this.editorId];
if (editor) {
editor.destroy(true);
}
});
}
}
You can't use formControlName
/formGroupName
/formArrayName
name without having a parent(or ancestor) formGroup
directive.
This means that you'll need to have something like this:
<form [formGroup]="yourFormGroup">
<!-- ... -->
<custom-element formControlName="name"></custom-element>
<!-- ... -->
</form>
However, if you don't want to worry about including it anywhere else, you can use the formControl
directive:
<custom-element [formControl]="yourFormControlInstance"></custom-element>