TinyMCE disappears in Blazor page

眉间皱痕 提交于 2020-06-27 12:48:07

问题


I want to use TinyMCE in a Blazor server side app, but it shows up on page load for a second and then disappears. I blame it on StatehasChanged() thus I have written an interop function that re-initializes TinyMCE and is called in the OnAfterRender() of the page.

This is the JS interop function:

initTinyMce: function (tinyMceID) { 
    tinymce.init({
        selector: 'textarea.tinyMce' 
    });
    return ""; 

    //var editor = tinyMCE.get(tinyMceID);
    //if (editor && editor instanceof tinymce.Editor) {
    //    editor.init();
    //}
}

In the OnAfterRender I call it like so:

protected override void OnAfterRender() {

    base.OnAfterRender();
    string a = jsInterop.InitTinyMce("myTinyMce").Result;
}

But still it disappears a second after it shows itself. How to fix this problem?


回答1:


I wasn't able to get it to mimic this behaviour so maybe you were using a different version of tinyMce and Blazor. I'm using TinyMce 5.3.1 and .Net Core 3.1. I see you switched to using SyncFusion but maybe this answer will help anyone else who comes along here looking to try to do this in Blazor like I was yesterday.

I think the main thing is disposing of the element when you navigate away and re-initializing when it comes into view / focus / is loaded / etc...

Here's a component that I put together last night that should take care of all the pieces and make it bind-able like a regular <InputTextArea>

I'm new to Blazor and components. This is the second bind-able form control I've made. If anyone has any comments or suggestions on how this could be better please edit or let me know and I can update. Thanks!

In the JS block in _Host.html (i'm using a local version of TinyMCE)

<script src="/js/tinymce/tinymce.min.js"></script>

/Shared/Components/Textarea.razor

<textarea id="@Id" @bind-value="Value" @bind-value:event="onchange" />

/Shared/Components/Textarea.razor.cs:

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Forms;
using Microsoft.JSInterop;

namespace Application.Shared.Components
{
    public partial class Textarea : ComponentBase, IDisposable
    {
        [Inject] private IJSRuntime JSRuntime { get; set; }

        [Parameter] public RenderFragment ChildContent { get; set; }

        [Parameter] public string Value { get; set; }

        [Parameter] public EventCallback<string> ValueChanged { get; set; }

        [Parameter] public string Id { get; set; } = null;

        private DotNetObjectReference<Textarea> _elementRef;

        [Parameter] public MenuModeEnum MenuMode { get; set; } = MenuModeEnum.standard;

        protected string FieldClass => GivenEditContext?.FieldCssClass(FieldIdentifier) ?? string.Empty;

        protected EditContext GivenEditContext { get; set; }

        protected FieldIdentifier FieldIdentifier { get; set; }

        protected string CurrentValue
        {
            get => Value;
            set
            {
                var hasChanged = !EqualityComparer<string>.Default.Equals(value, Value);
                if (!hasChanged) return;

                _ = value;

                Value = value;
                _ = ValueChanged.InvokeAsync(value);
                GivenEditContext?.NotifyFieldChanged(FieldIdentifier);
            }
        }

        protected override async Task OnInitializedAsync()
        {
            await base.OnInitializedAsync();
            this.Id = Id ?? Guid.NewGuid().ToString();
            _elementRef = DotNetObjectReference.Create(this);
        }

        protected override async Task OnAfterRenderAsync(bool firstRender)
        {
            if (firstRender)
            {
                await JSRuntime.InvokeVoidAsync("TinyMce.init", Id, Enum.GetName(typeof(MenuModeEnum), MenuMode), _elementRef);
            }
        }

        [JSInvokable("textArea_OnChange")]
        public void Change(string value)
        {
            CurrentValue = value;
        }

        protected virtual void Dispose(bool disposing)
        {
            JSRuntime.InvokeVoidAsync("TinyMce.dispose", Id, _elementRef);
        }

        void IDisposable.Dispose()
        {
            Dispose(disposing: true);
        }


        internal void DismissInstance()
        {
            JSRuntime.InvokeVoidAsync("TinyMce.dispose", Id, _elementRef);
            StateHasChanged();
        }
    }
}

/Shared/Components/Enums/MenuModeEnum.cs:

namespace Application.Shared.Components.Enums
{
    public enum MenuModeEnum
    {
        standard,
        minimal,
        grouped,
        bloated
    }
}

/wwwroot/js/site.js:

if (!window.TinyMce) {
    window.TinyMce = {};
}

window.TinyMce = {
    params : {
        standard: {
            plugins: 'code codesample link image autolink lists media paste table table spellchecker',
            toolbar1: 'undo redo | paste | removeformat styleselect | bold italic | alignleft aligncenter alignright alignjustify | outdent indent | link image media codesample | table | code | spellchecker',
            menubar: false,
            branding: false,
            toolbar_mode: 'floating'
        },
        minimal: {
            toolbar1: 'bold italic underline',
            menubar: false,
            branding: false,
            toolbar_mode: 'floating'
        },
        grouped: {
            plugins: "emoticons hr image link lists charmap table",
            toolbar: "formatgroup paragraphgroup insertgroup",
            toolbar_groups: {
                formatgroup: {
                    icon: 'format',
                    tooltip: 'Formatting',
                    items: 'bold italic underline strikethrough | forecolor backcolor | superscript subscript | removeformat'
                },
                paragraphgroup: {
                    icon: 'paragraph',
                    tooltip: 'Paragraph format',
                    items: 'h1 h2 h3 | bullist numlist | alignleft aligncenter alignright alignjustify | indent outdent'
                },
                insertgroup: {
                    icon: 'plus',
                    tooltip: 'Insert',
                    items: 'link image emoticons charmap hr'
                }
            },
            menubar: false,
            branding: false
        },
        bloated: {
            plugins: 'code codesample link image autolink lists media paste table table spellchecker',
            toolbar1: 'undo redo | styleselect | forecolor | bold italic underline strikethrough | link image media codesample | table | code | spellchecker',
            toolbar2: 'h1 h2 h3 | bullist numlist | alignleft aligncenter alignright alignjustify | outdent indent | emoticons charmap hr',
            menubar: false,
            branding: false,
            toolbar_mode: 'floating'
        }
    },
    init: function (id, mode, dotnetHelper) {
        var params = window.TinyMce.params[mode];
        params.selector = '#' + id;

        params.setup = function (editor) {
            editor.on('change', function (e) {
                console.log($('#' + id).val());
                $('#' + id).val(editor.getContent());
                $('#' + id).change();
                console.log($('#' + id).val());
                dotnetHelper.invokeMethodAsync("textArea_OnChange", $('#' + id).val());
            });
        }

        tinymce.init(params);
    },
    dispose: function (id, dotnetHelper) {
        tinymce.remove('#' + id);
    }
};

Usage:

<Textarea MenuMode="@MenuModeEnum.minimal" @bind-Value="@SomeObject.Comments" />


来源:https://stackoverflow.com/questions/57677035/tinymce-disappears-in-blazor-page

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!