我在网上搜索过,但找不到在 Angular 6/7 上使用
contenteditable
事件的方法。 Angular 似乎有一个混乱的解决方案,但该功能似乎并未延续到最新版本。
一个用例是在内容可编辑的
onChange
事件上,调用函数:
<div contententeditable="true" [change]="onNameChange(if.there.is.such.a.thing)">Type your name</div>
...
private name: string;
onNameChange(name) {
this.name = name;
}
对此有什么想法吗?谢谢。
您可以使用
input
事件,如下所示:
<div contenteditable (input)="onNameChange($event.target.innerHTML)">
Type your name
</div>
只需在元素和事件输入上设置一个变量,从innerText获取值
<h2 contenteditable="true" #x (input)="item.title = x.innerText">{{item.title}}</h2>
我使用 MutationObserver 来观察元素上的文本变化。 到目前为止效果很好:
import { isPlatformBrowser } from '@angular/common';
import {
Directive,
ElementRef,
OnDestroy,
OnInit,
PLATFORM_ID,
forwardRef,
inject,
input,
} from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import {
Observable,
Subject,
Subscriber,
filter,
fromEvent,
map,
take,
takeUntil,
} from 'rxjs';
import { assert } from './utils/assert';
@Directive({
selector: '[contentEditable]',
standalone: true,
host: {
'[contentEditable]': 'contentEditable()',
},
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => ContenteditableComponent),
multi: true,
},
],
})
export class ContenteditableComponent
implements ControlValueAccessor, OnInit, OnDestroy
{
// IO
///////////////
contentEditable = input.required<boolean | string>();
// Private attrs
protected disabled = false;
protected onChangesFn: (value: string) => void = () => {};
protected onTouchedFn: () => void = () => {};
private el = inject<ElementRef<HTMLElement>>(ElementRef);
private platformId = inject(PLATFORM_ID);
private readonly onDestroy$ = new Subject<void>();
constructor() {}
ngOnDestroy(): void {
this.onDestroy$.next();
this.onDestroy$.complete();
}
ngOnInit(): void {
assert(this.el.nativeElement);
if (isPlatformBrowser(this.platformId)) {
this.observeTextData(this.el.nativeElement)
.pipe(
takeUntil(this.onDestroy$),
filter(() => !this.disabled)
)
.subscribe((text) => {
this.onChangesFn(text ?? '');
this.onTouchedFn();
});
}
}
writeValue(text: any): void {
this.el.nativeElement.innerText = text;
}
registerOnChange(fn: (value: string) => void): void {
this.onChangesFn = fn;
}
registerOnTouched(fn: () => void): void {
fromEvent(this.el.nativeElement, 'focus')
.pipe(take(1), takeUntil(this.onDestroy$))
.subscribe(fn);
}
setDisabledState?(isDisabled: boolean): void {
this.disabled = isDisabled;
}
private observeTextData(el: HTMLElement) {
return new Observable((observer: Subscriber<MutationRecord>) => {
// Create an observer instance linked to the callback function
const mutationObserver = new MutationObserver((mutationList, _obsever) =>
mutationList.forEach((m) => observer.next(m))
);
// Start observing the target node for configured mutations
mutationObserver.observe(this.el.nativeElement, {
subtree: true,
characterData: true,
});
return mutationObserver.disconnect.bind(mutationObserver);
}).pipe(
filter((m) => m.type === 'characterData'),
map((m) => el.innerText)
);
}
}