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, время: 00:53. |