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>
|
<button type="button" (click)="toggleCode()">{{ showCode() ? 'Preview' : 'Code' }}</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@if (showCode()) {
|
|
||||||
<textarea
|
<textarea
|
||||||
class="html-editor-code"
|
class="html-editor-code"
|
||||||
rows="10"
|
rows="10"
|
||||||
|
[hidden]="!showCode()"
|
||||||
[value]="codeValue()"
|
[value]="codeValue()"
|
||||||
(input)="updateCode($any($event.target).value)"
|
(input)="updateCode($any($event.target).value)"
|
||||||
></textarea>
|
></textarea>
|
||||||
} @else {
|
|
||||||
<div
|
<div
|
||||||
#surface
|
#surface
|
||||||
class="html-editor-surface"
|
class="html-editor-surface"
|
||||||
|
[hidden]="showCode()"
|
||||||
contenteditable="true"
|
contenteditable="true"
|
||||||
(input)="onInput()"
|
(input)="onInput()"
|
||||||
></div>
|
></div>
|
||||||
}
|
|
||||||
</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 {
|
export interface HtmlEditorToolbarCommand {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -28,7 +28,7 @@ export const HTML_EDITOR_TOOLBAR: HtmlEditorToolbarCommand[] = [
|
|||||||
styleUrls: ['./marketplace-html-editor.component.scss'],
|
styleUrls: ['./marketplace-html-editor.component.scss'],
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
})
|
})
|
||||||
export class MarketplaceHtmlEditorComponent implements OnChanges {
|
export class MarketplaceHtmlEditorComponent implements OnChanges, AfterViewInit {
|
||||||
@Input() html = '';
|
@Input() html = '';
|
||||||
@Output() htmlChange = new EventEmitter<string>();
|
@Output() htmlChange = new EventEmitter<string>();
|
||||||
@ViewChild('surface', { static: true }) surface!: ElementRef<HTMLDivElement>;
|
@ViewChild('surface', { static: true }) surface!: ElementRef<HTMLDivElement>;
|
||||||
@@ -38,7 +38,19 @@ export class MarketplaceHtmlEditorComponent implements OnChanges {
|
|||||||
readonly codeValue = signal('');
|
readonly codeValue = signal('');
|
||||||
|
|
||||||
ngOnChanges(changes: SimpleChanges): void {
|
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 || '';
|
this.surface.nativeElement.innerHTML = this.html || '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user