最新消息:Welcome to the puzzle paradise for programmers! Here, a well-designed puzzle awaits you. From code logic puzzles to algorithmic challenges, each level is closely centered on the programmer's expertise and skills. Whether you're a novice programmer or an experienced tech guru, you'll find your own challenges on this site. In the process of solving puzzles, you can not only exercise your thinking skills, but also deepen your understanding and application of programming knowledge. Come to start this puzzle journey full of wisdom and challenges, with many programmers to compete with each other and show your programming wisdom! Translated with DeepL.com (free version)

javascript - TinyMCE disappears in Blazor page - Stack Overflow

matteradmin7PV0评论

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?

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?

Share Improve this question edited Sep 5, 2019 at 21:17 Michael Fromin 13.8k2 gold badges23 silver badges34 bronze badges asked Aug 27, 2019 at 14:35 mz1378mz1378 2,6127 gold badges31 silver badges50 bronze badges 3
  • Did you manage to find a solution to this issue? – Matthew Flynn Commented May 6, 2020 at 20:12
  • No. But I solved my problem by using syncfusion rich text editor it has a munity licence that is free and has all the ponents. But it has 5MB overhead (only rich editor js and css) – mz1378 Commented May 7, 2020 at 21:11
  • are you still having this issue? What versions are you using? I just got this working with TinyMce 5.3.1 and .Net Core 3.1. I made a bindable ponent to do it though. I can post it as an answer. – Ryan Vettese Commented May 29, 2020 at 16:51
Add a ment  | 

1 Answer 1

Reset to default 7

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 es 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 es into view / focus / is loaded / etc...

Here's a ponent 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 ponents. This is the second bind-able form control I've made. If anyone has any ments 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" />
Post a comment

comment list (0)

  1. No comments so far