I have an Angular component that injects Ace editor. Sometimes in logs (very rare) I can see the following error:
Error: ace.edit can't find div #aceEditor
at ie.edit (https://stepindev.com/ru/main.fcb9335868d1e005.js:1:1267133)
at t.ngAfterViewInit (https://stepindev.com/ru/main.fcb9335868d1e005.js:1:467814)
I have never been able to reproduce the issue. And I do not understand what can cause it. My understanding is that at the moment when ngAfterViewInit starts, the DOM is ready and can be used.
So the question is what can be the cause of the problem?
Component's template:
<div id="aceEditor" #editor></div>
<!--Don't recreate console with *ngIf. It must exists all the time to be able to capture all console input/output-->
<sid-console #console class="console" (change)="onIOAppeared()" hidden></sid-console>
<ng-content></ng-content>
ngAfterViewInit handler
import * as ace from 'ace-builds'
...
ngAfterViewInit(): void {
this.editor = ace.edit('aceEditor');
this.editor.setTheme('ace/theme/textmate');
this.editor.session.setMode('ace/mode/python');
this.editor.setOptions({
fontSize: '16pt'
});
this.editor.on("change", delta => this.change.emit(delta))
window.addEventListener(this.resizeEvenName, this.resizeEventListener, false);
// resize after all components above this one are settled. So we can get the correct "top" value
window.setTimeout(() => this.resizeComponents(), 0);
}
The container with this component is created dynamically depending on an HTTP request (using *ngIf):
<sid-robot-python-view [task]="$any(task)" *ngIf="isRobotPythonTask()" data-testId="robot-python-view"></sid-robot-python-view>
I would expect the the error never happens. It was logged for Chrome 130.0 and Chrome 109.0 on Windows. I use Angular 14.
According to the Ace editor docs - Edit Function accepts an element
instead of a string, could you try this method instead of passing in string.
Here we take a ViewChild
of the element, then we pass the nativeElement
to the ace editor edit
function.
import * as ace from 'ace-builds'
...
...
@ViewChild('aceEditor') aceEditor: ElementRef<any>;
...
ngAfterViewInit(): void {
if(this.editor?.nativeElement) {
this.editor = ace.edit(this.editor.nativeElement);
this.editor.setTheme('ace/theme/textmate');
this.editor.session.setMode('ace/mode/python');
this.editor.setOptions({
fontSize: '16pt'
});
this.editor.on("change", delta => this.change.emit(delta))
window.addEventListener(this.resizeEvenName, this.resizeEventListener, false);
// resize after all components above this one are settled. So we can get the correct "top" value
window.setTimeout(() => this.resizeComponents(), 0);
}
}