ngx-monaco-editor компонент сбрасывает form.pristine
Доброго времени суток.
Столкнулся со следующего рода проблемой. Я использую в проекте ngx-monaco-editor и присоединяю его к компоненту редактора в качестве FormControl-a в реактивной форме. Потом в onInit я загружаю данные и выставляю значения formControl-лов Я ожидал бы, что форма теперь будет нетронутой pristine: true, хотя на самом деле она помечена как pristine: false. Pristin-ом она становится из за компонента monaco, который после загрузки данных из форм-контрола сбрасывает это свойство. Даже сделав попытку пометить форму как pristine ничего не получилось, т.к. monaco работает асинхронно. Есть дурацкий вариант поместить markAsPristine в функцию setTimeout, но это как-то костыльно. На Гитлабе есть один opened issue с такой же проблемой. https://github.com/atularen/ngx-mona...tor/issues/101 Но он у меня не заработал. Событий изменений содержимого компонента он не отлавливает. <div> <ngx-monaco-editor #editorComponent [options]="editorOptions" formControlName="template" (onInit)="initMonaco($event)" ></ngx-monaco-editor> </div>
export class PostTemplateEditComponent implements ControlValueAccessor {
componentForm: FormGroup;
componentData: PostTemplate;
currId: string;
@ViewChild(EditorComponent, { static: false }) editorComponent: EditorComponent;
private _justSetValue: any;
private _onChange: any;
registerOnChange (fn: any): void {
this._onChange = fn;
this.editorComponent.registerOnChange((val: any) => {
// skip value if it is the just set value. relevant values are strings and `null`, so `===` is ok.
console.log("catch");
if(this._justSetValue === val) {
this._justSetValue = undefined;
return;
}
fn(val);
});
}
registerOnTouched (fn: any): void {
this.editorComponent.registerOnTouched(fn);
}
writeValue (val: any): void {
if(this._onChange) {
this._onChange(val);
this._justSetValue = val;
}
this.editorComponent.writeValue(val);
}
editorOptions = {
automaticLayout: true,
theme: 'vs-light',
language: 'handlebars',
minimap: {
enabled: false
}
};
}
initMonaco(monacoEditor: any) {
this.componentForm.controls.template.markAsPristine();
// не помогает
}
initState() {
this.componentForm = new FormGroup({
code: new FormControl(""),
name: new FormControl(""),
template: new FormControl(""),
is_active: new FormControl(null),
date_create: new FormControl({ value: "", disabled: true }),
date_modify: new FormControl({ value: "", disabled: true }),
});
}
ngOnInit() {
this.initState();
this.dataService.getItem<PostTemplate>(this.currId)
.subscribe((data: PostTemplate) => {
this.componentData = new PostTemplate(data);
this.componentForm.patchValue({
code: data.code,
name: data.name,
is_active: data.is_active,
template: data.template,
date_create: data.date_create,
date_modify: data.date_modify,
});
this.isReady = true;
});
} else {
this.isReady = true;
}
this.$formSubscr = this.componentForm.valueChanges
.subscribe(value => {
this.applyFormValues(value);
}
);
this.componentForm.markAsPristine();
}
Не подскажите почему не работает приведенный вариант кода, либо предложите вариант получше. |
shtangen,
ну вообще нужно ещё это https://github.com/atularen/ngx-mona...mponent.ts#L23, только в useExisting заюзать PostTemplateEditComponent. И formControlName="template" для ngx-monaco-editor не надо указывать. Вся обработка идет в обёртке. Соответственно ей и надо снаружи передавать эту директиву. |
Цитата:
Ваше решение не понял. До этого был вариант получить экземпляр редактора, завернутого в компонент и работать с ним напрямую без привязки к formControlName. Но такой вариант показался неудобным, так как реактивные формы позволяли упростить код. Получалось что то типа такого: <div class="scrolled-tab-content"> <ngx-monaco-editor #editorComponent class="template-editor" [options]="editorOptions" (onInit)="initMonaco($event)" ></ngx-monaco-editor> </div>
export class PostTemplateEditComponent {
editor: any;
initMonaco(monacoEditor: any) {
this.editor = monacoEditor;
}
ngOnInit() {
this.dataService.getItem<PostTemplate>(this.currId)
.subscribe((data: PostTemplate) => {
this.componentData = new PostTemplate(data);
this.componentForm.patchValue({
code: data.code,
name: data.name,
is_active: data.is_active,
date_create: data.date_create,
date_modify: data.date_modify,
});
// Инициализируем редактор
this.editor.setValue(data.template);
});
this.$formSubscr = this.componentForm.valueChanges
.subscribe(value => {
this.applyFormValues(value);
}
);
}
Или вы имели в виду что-то другое? Если есть возможность, приведите небольшой пример. Спасибо. |
shtangen,
именно это я и имел ввиду. а теперь снаружи где рисуется компонент PostTemplateEditComponent, ему и надо прокидывать formControlName, т.е. все ваши строчки с 9 по 27 должны быть на уровне выше по иерархии компонентов. PostTemplateEditComponent используется просто как прокси. app.component.ts
export class AppComponent {
ngOnInit() {
this.initState();
this.dataService.getItem<PostTemplate>(this.currId)
.subscribe((data: PostTemplate) => {
this.componentData = new PostTemplate(data);
this.componentForm.patchValue({
code: data.code,
name: data.name,
is_active: data.is_active,
date_create: data.date_create,
date_modify: data.date_modify,
});
// Инициализируем редактор
this.editor.setValue(data.template);
});
this.$formSubscr = this.componentForm.valueChanges
.subscribe(value => {
this.applyFormValues(value);
}
);
}
initState() {
this.componentForm = new FormGroup({
code: new FormControl(""),
name: new FormControl(""),
template: new FormControl(""),
is_active: new FormControl(null),
date_create: new FormControl({ value: "", disabled: true }),
date_modify: new FormControl({ value: "", disabled: true }),
});
}
app.component.html <div [formGroup]="componentForm"> <post-template-edit-component formControlName="template"> </post-template-edit-component> </div> |
Не слишком сложный оборот? Может проще обрабатывать monaco самостоятельно?
Поможет ли такая обертка избежать изменений внутри компонента? |
shtangen,
Всё должно быть нормально. Иногда самому приходилось делать похожие обёртки для различных компонентов. То есть мы создаем свой кастомный форм контрол, и в методах реализации интерфейса ControlValueAccessor: registerOnTouched, registerOnChange, writeValue - вызываем точно такие же методы оборачиваемого компонента. |
| Часовой пояс GMT +3, время: 05:11. |