serdarciplak / BlazorMonaco

Blazor component for Microsoft's Monaco Editor which powers Visual Studio Code.
https://serdarciplak.github.io/BlazorMonaco/
MIT License
437 stars 100 forks source link

Code editor is not disposed properly #136

Open FLAMESpl opened 1 month ago

FLAMESpl commented 1 month ago

Consider this file:

@page "/"
@using BlazorMonaco.Editor

<PageTitle>Home</PageTitle>

<h1>Hello, world!</h1>

<input @bind="content" />

<button @onclick="() => visible = !visible">Toggle</button>

@if (visible)
{
    <p>Visible!</p>
    <StandaloneCodeEditor Id="main-editor" CssClass="editor" ConstructionOptions="GetConstructionOptions" />
}

Welcome to your new app.

@code
{
    private string content = "{}";
    private bool visible = false;

    public StandaloneEditorConstructionOptions GetConstructionOptions(StandaloneCodeEditor editor) => new()
    {
        Language = "json",
        Value = content
    };

When button is pressed it toggles visibility of StandaloneCodeEditor. It either is added or removed from the DOM. When displayed for the first time, it correctly obtains value from input, but after every consecutive toggle value is not updated and remains the same in the editor.

EDIT:

I have made some digging and discovered this snippet when editor is created:


        if (oldEditor !== null) {
            options.value = oldEditor.getValue();
            window.blazorMonaco.editors.splice(window.blazorMonaco.editors.findIndex(item => item.id === id), 1);
            oldEditor.dispose();
        }

I have no idea why it is overriding new value in options with value from previous instance, I don't think of any scenario where it would be a desired behaviour.

I have managed to fix this issue by inserting this code to my App.razor:

<script>
    const blazorMonaco = window.blazorMonaco;
    const innerFunction = blazorMonaco.editor.create;

    blazorMonaco.editor.create = function(id, options, override, dotnetRef) {

        const oldEditor = blazorMonaco.editor.getEditor(id, true);

        if (oldEditor !== null) {
            blazorMonaco.editors.splice(blazorMonaco.editors.findIndex(item => item.id === id), 1);
            oldEditor.dispose();
        }

        innerFunction.call(this, id, options, override, dotnetRef);
    };
</script>
FLAMESpl commented 1 month ago

@serdarciplak I have created a PR to address this, can you take a look?