fix(project-editor): keep html-editor surface always in DOM
The @if/@else toggle between the contentEditable surface and the code
textarea broke the static ViewChild('surface') query: Angular never
resolves a static query for an element inside a conditional block, so
surface stayed undefined and every keystroke threw in emitChange().
Render both elements always and toggle visibility with [hidden]
instead, and add an ngAfterViewInit sync as a safety net for the
initial html input on the first change-detection pass.
This commit is contained in:
@@ -6,19 +6,19 @@
|
||||
<button type="button" (click)="toggleCode()">{{ showCode() ? 'Preview' : 'Code' }}</button>
|
||||
</div>
|
||||
|
||||
@if (showCode()) {
|
||||
<textarea
|
||||
class="html-editor-code"
|
||||
rows="10"
|
||||
[value]="codeValue()"
|
||||
(input)="updateCode($any($event.target).value)"
|
||||
></textarea>
|
||||
} @else {
|
||||
<div
|
||||
#surface
|
||||
class="html-editor-surface"
|
||||
contenteditable="true"
|
||||
(input)="onInput()"
|
||||
></div>
|
||||
}
|
||||
<textarea
|
||||
class="html-editor-code"
|
||||
rows="10"
|
||||
[hidden]="!showCode()"
|
||||
[value]="codeValue()"
|
||||
(input)="updateCode($any($event.target).value)"
|
||||
></textarea>
|
||||
|
||||
<div
|
||||
#surface
|
||||
class="html-editor-surface"
|
||||
[hidden]="showCode()"
|
||||
contenteditable="true"
|
||||
(input)="onInput()"
|
||||
></div>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ChangeDetectionStrategy, Component, ElementRef, EventEmitter, Input, OnChanges, Output, SimpleChanges, ViewChild, signal } from '@angular/core';
|
||||
import { AfterViewInit, ChangeDetectionStrategy, Component, ElementRef, EventEmitter, Input, OnChanges, Output, SimpleChanges, ViewChild, signal } from '@angular/core';
|
||||
|
||||
export interface HtmlEditorToolbarCommand {
|
||||
id: string;
|
||||
@@ -28,7 +28,7 @@ export const HTML_EDITOR_TOOLBAR: HtmlEditorToolbarCommand[] = [
|
||||
styleUrls: ['./marketplace-html-editor.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class MarketplaceHtmlEditorComponent implements OnChanges {
|
||||
export class MarketplaceHtmlEditorComponent implements OnChanges, AfterViewInit {
|
||||
@Input() html = '';
|
||||
@Output() htmlChange = new EventEmitter<string>();
|
||||
@ViewChild('surface', { static: true }) surface!: ElementRef<HTMLDivElement>;
|
||||
@@ -38,7 +38,19 @@ export class MarketplaceHtmlEditorComponent implements OnChanges {
|
||||
readonly codeValue = signal('');
|
||||
|
||||
ngOnChanges(changes: SimpleChanges): void {
|
||||
if (changes['html'] && this.surface && this.surface.nativeElement.innerHTML !== (this.html || '')) {
|
||||
if (changes['html']) {
|
||||
this.syncSurfaceFromInput();
|
||||
}
|
||||
}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
// Safety net: on the very first change detection pass, ngOnChanges can run
|
||||
// before the static ViewChild is resolved, so re-sync once the view is ready.
|
||||
this.syncSurfaceFromInput();
|
||||
}
|
||||
|
||||
private syncSurfaceFromInput(): void {
|
||||
if (this.surface && this.surface.nativeElement.innerHTML !== (this.html || '')) {
|
||||
this.surface.nativeElement.innerHTML = this.html || '';
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user