Search code examples
c#blazor.net-8.0mudblazor

Submit form with empty field breaks the connection with error: Cannot read properties of null (reading 'removeChild'))


I have this blazored text editor, where I am trying to edit a blog item, the problem is that when I am trying to submit a blog with an empty title, it breaks the connection and the application freezes. The error that is received is:

System.AggregateException: One or more errors occurred. (TypeError: Cannot read properties of null (reading 'removeChild'))
 ---> System.InvalidOperationException: TypeError: Cannot read properties of null (reading 'removeChild')
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.InvokeRenderCompletedCallsAfterUpdateDisplayTask(Task updateDisplayTask, Int32[] updatedComponents)

This is the component

@using BlazorBlog.Application.Features.Blogs.Commands.Edit

@inherits MudComponentBase

@inject IValidationService Validator
@inject IMediator Mediator

<MudDialog style="min-height: 650px;">
    <DialogContent>
        <MudForm Model="@Model" @ref="@_form" Validation="@(Validator.ValidateValue(Model))">
            <MudGrid>
                <MudItem xs="12">
                    <MudTextField Label="Blog Title" @bind-Value="Model.Title" For="@(() => Model.Title)"
                                  Required RequiredError="@string.Format(ConstantString.RequiredText, "Blog Title")">
                    </MudTextField>
                </MudItem>
                <MudItem xs="12">
                    <BlazoredTextEditor @ref="@RichEditor">
                        <ToolbarContent>
                            <span class="ql-formats">
                                <select class="ql-font">
                                    <option selected=""></option>
                                    <option value="serif"></option>
                                    <option value="monospace"></option>
                                </select>
                                <select class="ql-size">
                                    <option value="small"></option>
                                    <option selected=""></option>
                                    <option value="large"></option>
                                    <option value="huge"></option>
                                </select>
                            </span>
                            <span class="ql-formats">
                                <button class="ql-bold"></button>
                                <button class="ql-italic"></button>
                                <button class="ql-underline"></button>
                                <button class="ql-strike"></button>
                            </span>
                            <span class="ql-formats">
                                <select class="ql-color"></select>
                                <select class="ql-background"></select>
                            </span>
                            <span class="ql-formats">
                                <button class="ql-list" value="ordered"></button>
                                <button class="ql-list" value="bullet"></button>
                                <button class="ql-indent" value="-1"></button>
                                <button class="ql-indent" value="+1"></button>
                                <select class="ql-align">
                                    <option selected=""></option>
                                    <option value="center"></option>
                                    <option value="right"></option>
                                    <option value="justify"></option>
                                </select>
                            </span>
                            <span class="ql-formats">
                                <button class="ql-link"></button>
                            </span>
                        </ToolbarContent>
                        <EditorContent>
                            @((MarkupString)Model.Description)
                        </EditorContent>
                    </BlazoredTextEditor>
                </MudItem>
            </MudGrid>
        </MudForm>
    </DialogContent>
    <DialogActions>
        <MudButton Variant="Variant.Outlined" OnClick="Cancel">@ConstantString.Cancel</MudButton>
        <MudLoadingButton Variant="Variant.Outlined" Loading="@_saving" OnClick="Submit">@ConstantString.SaveChanges</MudLoadingButton>
    </DialogActions>
</MudDialog>

@code {
    [CascadingParameter] private IMudDialogInstance MudDialog { get; set; } = default!;
    [EditorRequired][Parameter] public EditBlogCommand Model { get; set; } = default!;
    [Parameter] public Action? Refresh { get; set; }
    private MudForm? _form;
    private bool _saving;
    BlazoredTextEditor RichEditor;

    private async Task Submit()
    {
        try
        {
            _saving = true;

            await _form.Validate().ConfigureAwait(false);

            try
            {
                Model.Description = await RichEditor.GetHTML();
            }
            catch (Exception)
            {
                return;
            }

            if (!_form!.IsValid) { return; }

            var result = await Mediator.Send(Model);

            if (result.Succeeded)
            {
                MudDialog.Close(DialogResult.Ok(true));
                Snackbar.Add(ConstantString.SaveSuccess, Severity.Info);
            }
            else
            {
                Snackbar.Add(result.ErrorMessage, Severity.Error);
            }
        }
        finally
        {
            _saving = false;
        }
    }

    private void Cancel()
    {
        MudDialog.Cancel();
    }
}

I tried to refactor this component but that gave me some issues in fetching the text from the editor.


Solution

  • The problem is most likely about this line of code:

    @((MarkupString)Model.Description)
    

    You need to retrieve the value with RichEditor.GetHTML()

    Blazored text editor has some great samples on their Github page: https://github.com/Blazored/TextEditor/tree/main

    The error occurs because the text editor is manipulating the same DOM that Blazor is rendering to. Which creates a mismatch and triggers the removeChild error.