Is there a proper way to wire up Trix editor with Livewire?
Asked Answered
S

4

6

When wiring together Trix editor content with Livewire, I am stumbling into problems. I believe that the issue is that when Livewire receives content from Trix, the content is swapped out and Trix becomes disabled. Is there a better way?

What I have done, that works, is as follows. At the moment, the page is the redirected to itself in order to reboot Trix (defeating the whole point of Livewire, but it's being used for other things too).

<div>
  <input
      id="newCommentTextTrixContent"
      type="hidden"
      wire:model="newCommentText"
  >

  <trix-editor
      id="newCommentTextTrixEditor"
      input="newCommentTextTrixContent"
  ></trix-editor>


  <button wire:click="addComment(document.getElementById('newCommentTextTrixEditor').innerHTML)">Add Comment</button>
</div>

I have tried

  • wire:model on the hidden input -- nothing happens
  • x-on:trix-change="$set('comment', $event.target.innerHTML) -- this works, but Trix goes grey and ceases to work after the first keypress (reboot problem?)

I'm sure something like the latter is better, but with Trix somehow being rebooted each time. It all seems a bit messy - so the question is, what's the right way to do this?

Suberin answered 5/3, 2020 at 6:56 Comment(4)
Did you figure this out? Trying to integrate trix with livewire now and running into similar problems. Thanks.Krishna
@Krishna not yet! Star / upvote it to keep an eye on it :) I'll post any answers back here if I find them.Suberin
@Krishna if you only need one item on a page, then this works: gist.github.com/tanthammar/20a70865415f9f84ec4cca054f3b8396Suberin
Hi @Krishna - there's now a working answer below! I think Livewire has had some updates, as this was much easier to get going than I recall.Suberin
S
16

I got it working. With up to date Livewire and Alpine installations, the code is roughly as follows.

    <div wire:ignore>
        <trix-editor
            class="formatted-content"
            x-data
            x-on:trix-change="$dispatch('input', event.target.value)"
            x-ref="trix"
            wire:model.debounce.60s="newCommentText"
            wire:key="uniqueKey"
        ></trix-editor>
    </div>

Why does this work?

  • You need wire:ignore on the parent node, because Trix inserts the toolbar above the text area. wire:ignore stops Livewire from worrying about it and therefore not removing it or messing with it on the next cycle.
  • You need a wire:key because the DOM moves around a bit, and this helps Livewire to keep track of it.
  • I propose the long debounce, which is a hack as the .lazy modifier doesn't work well with text. Also, waiting for Ajax on each key press is painful.
  • The alpine event ensures that Trix events (like bold, italics etc) are still fired

That's it. I use this above to repetitively submit comments onto the end of a comment stream, and everything seems to work fine. Good luck!

Note, I also have CKEditor working similarly, as described here.

Suberin answered 14/5, 2020 at 11:29 Comment(7)
Thanks for the follow up. Will be trying this out over the weekend. Also, Caleb is about to release a few Screencasts covering this exact thing.Krishna
@Kurucu This seems to work very well. But when I apply styles like li or bold it doesnt retain in the wire:model. Ex: <div>foo<br>bar<br>foobar</div> I applied the Bullets here the tags are missing. Did you face this issue?Two
@Two I’ve not seen this. Have you checked the DB? do you have any filters installed?Suberin
@Krishna if you’re a sponsor - I don’t think they’re going to be free! Hopefully fixed anyway 🙂Suberin
@kurucu, there are no filters. Just plain trix tags. Is there anyway we can connect and screen share? If it is totally cool with you.Two
you save my life . i has been tried more then 1 week. but no solution.Character
Thanks. Just need to add .self modifier x-on:trix-change.self to prevent dispatching from another instances of trix.Quintana
Z
6

As an extension on @Kurucu 's answer, and the comment under it from @Rehan;

This seems to work very well. But when I apply styles like li or bold it doesnt retain in the wire:model. Ex: <div>foo<br>bar<br>foobar</div> I applied the Bullets here the tags are missing. Did you face this issue? – Rehan

To fix the issue of not having an updated value when pressing buttons bold, italic, or quote for example, add the following part to the trix editor (note the x-on:trix-change="$dispatch('input', event.target.value)"):

<div wire:ignore>
    <trix-editor
        class="formatted-content"
        x-data
        x-on:trix-change="$dispatch('input', event.target.value)"
        wire:model.debounce.1000ms="newCommentText"
        wire:key="uniqueKey"
    ></trix-editor>
</div>
Zugzwang answered 9/7, 2020 at 16:17 Comment(1)
Thanks a lot - I was stuck at the above issue and this did the trick!Prickly
A
1

The above option works but wasn't getting the data back from my field, Here's what worked for me with a little tweak using AlpineJS's @entangle. Below is my working solution:

<div class="mb-2" x-data="{ description: @entangle('description').defer }"

             x-init="$watch('description', function (value) {
                        $refs.trix.editor.loadHTML(value)
                        var length = $refs.trix.editor.getDocument().toString().length
                        $refs.trix.editor.setSelectedRange(length - 1)
                        }
                    )" wire:ignore>

            <label class="form-label">Job Description <span class="text-danger">*</span></label>
            @error('description')
            <span class="error d-inline-block"><i class="mdi mdi-alert-circle"> </i> {{$message}}</span>
            @enderror
            <input name="description" id="description" type="hidden" x-model="description">
            <div x-on:trix-change.debounce.1000ms="description = $refs.trix.value">
                <trix-editor x-ref="trix" input="description" class="overflow-y-scroll"
                             style="height: 20rem;"></trix-editor>
            </div>
        </div>
Acey answered 9/7, 2021 at 11:20 Comment(1)
There is debate on this way of using it here: gist.github.com/tanthammar/20a70865415f9f84ec4cca054f3b8396Suberin
P
0

I got it to work by using Trix's built-in events.

<input id="about" name="about" type="hidden" value="{{ $about }}">
<trix-editor input="about" class="wysiwyg-content"></trix-editor>

<script>
    var about = document.getElementById("about")

    addEventListener("trix-change", function(event) {
        console.log(about.getAttribute('value'));
        @this.set('about', about.getAttribute('value'))
    })
</script>
Pavlodar answered 20/4, 2020 at 20:35 Comment(1)
This might become hard to replicate if you have lots of editors on the screen at once?Suberin

© 2022 - 2024 — McMap. All rights reserved.