0

I have a Livewire component that uses CKEditor 5 (also tested with 4).

I have based my adaptation on this post on Laracast forum and some others: https://laracasts.com/discuss/channels/laravel/how-to-bind-ckeditor-value-to-laravel-livewire-component

This component is reused throughout the admin panel it’s part of. This is part of a complex model that has many relationships that need to be saved individually so the controller methods don’t get jammed. The reason for Livewire.

I do have a button to save some of the properties that belong only to the parent model, but I am hoping to have all other relationships saved via Livewire and not adding any other save button. I don’t what the user to get confused.

Now this works but I am unable to get it to work with lazy or debounce. It fires a request on about every key strokes.

I have also tried a timeout, but this does only delay the requests. All requests get sent after the timeout anyway. I have tried to change the event name “change:data” to what I could find from CKEditor, that didn’t work.

Is there a way to either fix or get around it so it fires one request after x amount of time with the actual content at that time?

I am presently going through the CKEditor events documentation to try to find a working solution…

Also getting into Alpinejs... Probably the best choice. Not yet familiar with it.

Thanks,

Call the component


    @livewire( "rich-text-input", [ "plant" => $plant, "relation" =>"description", "modelName" => "description" ] )

RichTextInput.php

    class RichTextInput extends Component
    {
    
        public string $modelName;
    
        public string $content;
    
        public Plant $plant;
    
        public string $relation;
    
        public string $timeout;
    
        public bool $disabled;
    
        protected array $rules = [
            "content" => "required|string"
        ];
    
    
        public function mount( Plant $plant, $relation, $modelName )
        {
            $this->content = $plant->{$relation}()->first()->content ?? "";
            $this->relation = $relation;
            $this->modelName = $modelName;
            $this->timeout = config( "website.settings.timeout" );
            $this->disabled = !$plant->id;
        }
    
    
        public function updatedContent()
        {
            $this->validate();
            $plant = $this->plant->{$this->relation}()->updateOrCreate(
                ["plant_id" => $this->plant->id],
                [ "content" => $this->content, "lang" => "fr" ],
            );
        }

        public function render()
        {
            return view('livewire.rich-text-input');
        }
    }

rich-text-input.blade.php

<div wire:ignore wire:model.lazy="{{ $modelName }}" wire:key="{{ $modelName }}" class="{{ $disabled ? "disabled" : "" }}" >
    @csrf

    <textarea   id="{{ $modelName }}" name="{{ $modelName }}" >{{ $content }}</textarea>

    <script>

        ClassicEditor
            .create( document.querySelector( '#{{ $modelName }}' ) )
            .then( editor => {

                @if ( $disabled )
                    editor.readOnly = true;
                @else
                    editor.model.document.on( "change:data", async () => {
                   
                        @this.set( 'content',  editor.getData() );
                    })
                @endif
            })
            .catch( error => {
                console.error( error );
            });
    </script>
</div>
Marc DG
  • 51
  • 10
  • https://laravel-livewire.com/docs/2.x/properties#debouncing-input Try increasing the 500ms to suit your needs. – nlta Feb 17 '22 at 01:35
  • @nlta - I tried that before. CKEditor and probably most of these type of rich text editor take the place of the actual component in the DOM and therefore renders some functionalities to not work. – Marc DG Feb 17 '22 at 02:12

2 Answers2

1

in your javascript you should add a listener to you submit button within creation on editor :

ClassicEditor.create(document.querySelector('#body'), {
    extraPlugins: [ SimpleUploadAdapterPlugin ,  ],

} ).then(editor => {

    document.querySelector("#submit").addEventListener("click",() =>{
        let body = $("#body").data("body")
        eval(body).set("body",editor.getData())
    })

}).catch(error => {
    console.error(error);
})

and in your blade make sure to do the same : <textarea id="body" data-body="@this" wire:model="body" ></textarea>

and

<button id="submit" wire:click="savePost" class="btn btn-dark btn-rounded pd-x-20">save</button>

0

It turns out that I had the solution under my nose. On the same link as above, one of the posts was an Alpinejs solution to the problem.

https://laracasts.com/discuss/channels/laravel/how-to-bind-ckeditor-value-to-laravel-livewire-component?reply=607889

The only thing I am not sure yet, is the editor.readOnly = true. If it as any true impact. I am disabling the component if the main model is not saved yet. Only way it was effective to disable was through CSS pointer-events: none;

<textarea {{ ( $disabled )? "disabled" : "" }}
    class="form-textarea w-full {{ ( $disabled )? "disabled" : "" }}"
    x-data
    x-init="
           ClassicEditor.create( $refs.{{ $modelName }})
            .then( function( editor ){
                if(  {{ json_encode( $disabled ) }}  ) {
                    editor.readOnly = true
                   
                }else{
                    editor.model.document.on( 'change:data', () => {
                       $dispatch( 'input', editor.getData() )
                    })
                }
            })
            .catch( error => {
                console.error( error );
            } );
        "
    wire:ignore
    wire:key="{{ $modelName }}"
    x-ref="{{ $modelName }}"
    wire:model.debounce.5000ms="content"
>{!! $content !!}</textarea>
Marc DG
  • 51
  • 10
  • I ran into this issue a while back. I solved it by simply adding a listener on my submit button calling a function with @this.set( 'content', editor.getData() ); inside it. – rbruhn May 02 '22 at 15:53