tinymce / tinymce-angular

Official TinyMCE Angular Component
MIT License
320 stars 92 forks source link

TinyMCE inside an Angular reactive form retrieves every embedded remote image on every keypress #376

Open 13-gregabytes opened 2 months ago

13-gregabytes commented 2 months ago

What is the current behavior?

I have TinyMCE-Angular inside an reactive form.
I embedded a remote image in the text.
On every keypress in the editor, I see, in my network tab, a request is made to retrieve the image.

Please provide the steps to reproduce and if possible a minimal demo of the problem via codesandbox.io or similar.

I first noticed this behaviour in my application. I didn't know if there was something wrong with my implementation so I decided to install TinyMCE-Angular in a new project on its own.

I installed TinyMCE-Angular using this document: https://www.tiny.cloud/docs/tinymce/latest/angular-pm/

I didn't see the behaviour in this bare bones project so I installed reactive forms.

I added the reactive form using this blog post: https://www.tiny.cloud/blog/angular-rich-text-editor/

With TinyMCE-Angular inside a reactive form, I then noticed the behaviour of embedded remote image retrieval with every keypress.

What is the expected behavior?

Do not retrieve remote images with every keypress in the editor.

Which versions of TinyMCE/TinyMCE-Angular, and which browser / OS are affected by this issue? Did this work in previous versions of TinyMCE or TinyMCE-Angular?

I have noticed this with version 6 and version 7. I do not know what the behaviour is for older versions.

13-gregabytes commented 2 months ago

I've traced this to the following code.

From the tinymce project, in modules/tinymce/src/core/main/ts/dom/DomSerializerPreProcess.ts,
in the preProcess function,
the line let clonedNode = node.cloneNode(true) as Element;.
When the node.cloneNode(true) is called, this triggers a request for all remote images.

This is being triggered from the tinymce-angular project in tinymce-angular-component/src/main/ts/editor/editor.component.ts
by the emitOnChange function being triggered by a subscription to the Observable returned from listenTinyMCEEvent for the modelEvents.

listenTinyMCEEvent(editor, this.modelEvents, this.destroy$).subscribe(() => {
  this.ngZone.run(() => this.emitOnChange(editor));
});

For my purposes, adding a debounceTime(1000) before the subscribe of the listenTinyMCEEvent for the modelEvents was effective in lowering the number of requests made to the remove images.

listenTinyMCEEvent(editor, this.modelEvents, this.destroy$)
    .pipe(debounceTime(1000))
    .subscribe(() => {
        this.ngZone.run(() => this.emitOnChange(editor));
    });

I am not sure if this has any unintended side effects but it does stops image requests from occurring until a user stops typing for 1 second.

danoaky-tiny commented 2 months ago

@13-gregabytes Could you please provide a replication case. You can fork our code-sandbox if you wish.

13-gregabytes commented 2 months ago

I have created a code-sandbox BUT the issue does not happen there. I needed to modify the code in the sandbox from my original to get it to run.

I do have a GitHub repo where the issue does occur. As stated in my first post, I built this demo using the following tinymce-angular documentation

danoaky-tiny commented 1 week ago

I've had a look at the repo you provided. I seem to only be able to replicate on chrome and with network cache disabled. This also seems to just be an issue with any call made to editor.getContent, which is what the form control is doing here.

In this case, I would suggest the workaround you've already found or perhaps not using form control and instead retrieving the editor's content on form submission instead.