suneditor icon indicating copy to clipboard operation
suneditor copied to clipboard

How to using in livewire

Open Saeeed-B opened this issue 3 years ago • 5 comments

@JiHong88 hi. How to using with livewire framework? How to use wire:model? With Ex please.

Saeeed-B avatar Jun 26 '21 06:06 Saeeed-B

@Saeeed-B Sorry, I don't know well of the livewire framework. :(

JiHong88 avatar Jun 26 '21 07:06 JiHong88

Are u still interested in how to use SunEditor with Livewire & Alpine.JS? I've implemented this just a few days ago and it work's like a charme until now 8-) Could write a possible solution on interest...

kaju74 avatar May 05 '22 09:05 kaju74

Absolutely! I think it would be very good.

JiHong88 avatar May 05 '22 15:05 JiHong88

Okay, here we go 8-)

In our Livewire component, we need a public variable to store the content. This could be a 'normal' string variable or an eloquent field from our model (e.g. public Post $post;). Make sure you include this field in the validation rules() of the livewire component to get the form attributes after submitting it (e.g. $attributes = $this->getValidatedAttributes()). Take a look at the livewire documentation if you're not familiar with this form processing stuff.

To be able to use the SunEditor in our form, the easiest way is to create a blade component for this. This component can then be used in our Livewire blade template as usual:

<x-suneditor wire:model.defer="post.description">
    My post content
</x-suneditor>

Use the "defer" directive to get rid of unneccessary server calls.

Now we take a look at our blade component. To be able to use multiple SunEditor's in one form, we first need to create unique names for all instances. The simpliest way is to include a small php call in our blade component for this:

@php
    $name = $attributes->wire('model')->value();
@endphp

The $name variable includes now the name of the linked wire model (i.e. "post.description") and can be used for the textarea and an optional html label tag:

<textarea x-data="editor($el, @entangle($attributes->wire('model')))" name="{{ $name }}" x-cloak></textarea>
<label for="{{ $name }}">
    {{ $slot }}:
</label>

The "$slot" will be replaced with our content above ("My post content") and is used for the textarea label. The textarea itself injects Alpine.js via the "x-data" directive and uses the "@entangle" keyword to 2-way-link Alpine with our Livewire model. The "x-cloak" custom html attribute is used to hide the textarea while loading the content. It's defined in the "app.css" file of our Laravel application:

/**
 * Alpine.js styling.
 */
[x-cloak] {
    visibility: hidden;
    overflow: hidden;
    display: none;
}

I always try to separate larger Alpine.js logic from my blade components, so I call the "editor" function which code is placed in it's own file. So let's take a look at the "app.js" file of our app first:

/**
 * Alpine.js library.
 *
 * You can find the documentation here:
 * https://github.com/alpinejs/alpine
 */
import Alpine from 'alpinejs';

// set alpine available via global window
window.Alpine = Alpine;

// inject custom components
require('./components/suneditor');

// start it!
Alpine.start();

We include the SunEditor functionality by 'require'-ing the separate Javascript file (suneditor.js) in the 'components'-subfolder:

import SunEditor from "suneditor";
import {align, blockquote, fontColor, hiliteColor, list, table, link} from 'suneditor/src/plugins'

document.addEventListener('alpine:init', () => {
    Alpine.data('editor', (el, model) => ({
        value: model,
        init() {
            let parent = this;

            let editor = SunEditor.create(el, {
                value: this.value,
                plugins: [align, blockquote, fontColor, hiliteColor, list, table, link],
                buttonList: [
                    ...
                ],
            });

            editor.onChange = function (contents) {
                parent.value = contents;
            }
        }
    }))
})

First, we need to make sure that Alpine.js has finished it's initialization stuff. Then we define our 'editor'-function with accepts just two parameters: "el" and "model". The "el" passes the textarea element from the dom to be used and the "model" holds the Livewire model defined. Then we create a new SunEditor instance with the plugins to use (and some other stuff you need). To fill the editor with the previously stored content, we only need to set the 'value' variable. To update the wire model, we hook into the "onChange" callback from SunEditor. At this point, we just fill the value with the new content - that's it.

kaju74 avatar May 09 '22 16:05 kaju74

i use like this:

 const editor = SUNEDITOR.create();
  editor.onChange = function (contents, core) {
      @this.set('Content', core);
  }

this is very simple and apline is not required

Saeeed-B avatar Jun 05 '22 13:06 Saeeed-B