leonvr's avatar

How update TinyMCE Rich Text Editor content with a Livewire variable?

Hi, If I update a Livewire value and want to display that in my Rich Text Editor (RTE), the RTE-div disappears. I can not use wire:ignore because I want the updated value to be displayed inside the RTE. I made a little component demonstrating this unwanted behaviour. The PHP file:

<?php

namespace App\Livewire;

use Livewire\Component;

class TestRte extends Component
{
    public $lw1;
    public $rtecontent;

    public function mount()
    {
        $this->lw1 = 1;
    }

    public function render()
    {
        return view('livewire.test-rte');
    }

    public function add()
    {
        $this->lw1 = $this->lw1 + 1;
    }
}

The Blade file:

<div>
    <p>Test Rte component</p>
    <div>{{ $lw1 }}</div>

    <div>
        <button wire:click="add()" class="bg-red-100 p-3 border rounded border-red-400 mb-1">Add 1 using
            Livewire</button>
    </div>

    <div id="mailcontent" class="hidden">
        <p>Before</p>
        <p><b>{{ $lw1 }}</b></p>
        <p>After</p>
    </div>

    <div>
        <textarea id="mailtekst" rows="11"></textarea>
    </div>

    @push('scripts')
    <script src="https://cdn.tiny.cloud/1/c7b550yn0arymkbnttlir9539w3zjxav8ermgd3kib08xchp/tinymce/5/tinymce.min.js"
        referrerpolicy="origin"></script>

    <script>
        tinymce.init({
            selector: 'textarea#mailtekst',
            height: 300,
            menubar: false,
            toolbar: 'undo redo | bold italic | fontselect | forecolor | removeformat',
            content_style: 'body { line-height: 1.1; }',
            setup: function (editor) {
                editor.on('init', function () {
                    editor.setContent(document.getElementById('mailcontent').innerHTML);
                });
            }
        });
    </script>
    @endpush
</div>

So initially everything is fine. The following is shown (is it possible to add an image here?): above the button '1' and inside the RTE 'Before 1 After'. But after clicking the button it goes wrong: above the button '2' (is correct), but the RTE disappears.

An important note: using Livewire version 2 this was working ok. Now I upgraded to Livewire version 3 this error occurs.

0 likes
3 replies
LaryAI's avatar
Level 58

To solve the issue of the disappearing RTE when updating the Livewire variable, you can use Livewire's JavaScript hooks to manually update the TinyMCE content when the Livewire component updates. Here's how you can do it:

  1. Add a Livewire event listener for the updated event in your component.
  2. Use the tinymce.get() method to get the TinyMCE instance and then update its content with the new value.

Here's the updated Blade file with the necessary changes:

<div>
    <p>Test Rte component</p>
    <div>{{ $lw1 }}</div>

    <div>
        <button wire:click="add()" class="bg-red-100 p-3 border rounded border-red-400 mb-1">Add 1 using Livewire</button>
    </div>

    <div id="mailcontent" class="hidden">
        <p>Before</p>
        <p><b>{{ $lw1 }}</b></p>
        <p>After</p>
    </div>

    <div>
        <textarea id="mailtekst" rows="11"></textarea>
    </div>

    @push('scripts')
    <script src="https://cdn.tiny.cloud/1/c7b550yn0arymkbnttlir9539w3zjxav8ermgd3kib08xchp/tinymce/5/tinymce.min.js"
        referrerpolicy="origin"></script>

    <script>
        document.addEventListener('livewire:load', function () {
            tinymce.init({
                selector: 'textarea#mailtekst',
                height: 300,
                menubar: false,
                toolbar: 'undo redo | bold italic | fontselect | forecolor | removeformat',
                content_style: 'body { line-height: 1.1; }',
                setup: function (editor) {
                    editor.on('init', function () {
                        editor.setContent(document.getElementById('mailcontent').innerHTML);
                    });
                }
            });

            window.livewire.hook('message.processed', (message, component) => {
                if (component.fingerprint.name === 'test-rte') {
                    var content = document.getElementById('mailcontent').innerHTML;
                    tinymce.get('mailtekst').setContent(content);
                }
            });
        });
    </script>
    @endpush
</div>

In this solution, we've added a Livewire hook message.processed that listens for updates to the Livewire component. When the component is updated, we get the new content from the hidden #mailcontent div and set it as the content of the TinyMCE editor using tinymce.get('mailtekst').setContent(content);.

Make sure to replace 'test-rte' with the actual name of your Livewire component if it's different.

This approach allows you to keep the RTE in sync with the Livewire variable without using wire:ignore, which would prevent updates from being reflected in the RTE.

leonvr's avatar

@LaryAI This does not work. Already initially the RTE is not showing.

Please or to participate in this conversation.