Почему добавленный ckeditor в приложение Laravel 11 теряется, когда я начинаю печатать внутри области ckeditor?

Чтение https://startutorial.com/view/using-ckeditor-with-laravel-livewire статья Я добавил ckeditor в приложение Laravel 11 на 1 странице, как в примере, и все работает нормально.

Но чтобы в редакторе был текст по умолчанию, я переделал его так:

    <div class = "flex flex-col space-y-10">
        <div wire:ignore>
            <textarea wire:model = "message"
                      class = "min-h-fit h-48 "
                      name = "message"
                      id = "message">{{ $message }}</textarea>
        </div>

        <div>
            <span class = "text-lg">You typed:</span>
            <div class = "w-full min-h-fit h-48 border border-gray-200">{{ $message }}</div>
        </div>
    </div>

Поместить $message внутри блока textarea было для меня решением — возможно, не лучшим.

Итак, у меня есть редактор с ckeditor и текстом по умолчанию, но когда я начинаю вводить текст внутри области ckeditor - сам ckeditor теряется. и я вижу простое текстовое поле, а в блоке «Вы набрали» я вижу новый текст.

У меня есть редактор компонентов:

namespace App\Livewire\Admin;

use App\Enums\AppColorEnum;
use App\Enums\ConfigValueEnum;
use App\Enums\DispatchAlertTypeEnum;
use App\Library\ImageProps;
use App\Library\Traits\AppCommonTrait;
use App\Livewire\Forms\NewsCategoryForm;
use App\Models\NewsCategory;
use App\Rules\NewsCategoryRules;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Database\QueryException;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Livewire\Attributes\On;
use Livewire\Component;
use Livewire\WithFileUploads;
use NewsCategoryActiveEnum;

class NewsCategoryEditor extends Component
{
    use AppCommonTrait;
    use WithFileUploads;
    public string $pageTitle = 'News category editor';
    public ?int $id = null;
    public bool $isEdit = false;
    public NewsCategoryForm $form;
    public array $imageProps = [];
    public array $activeSelectionItems = [];
    public array $appColorSelectionItems = [];

    public function render()
    {
        return view('livewire.admin.news-category-editor')->layout('components.layouts.admin');
    }

    public function mount(?int $id = null, ?string $defaultAction = null)
    {
        ...
        if (!blank($id)) {
            $this->edit($id);
        }
    }

    public function edit($id)
    {
        $this->isEdit = true;
        try {
            $newsCategory = NewsCategory::getById($id)->firstOrFail();
        } catch (ModelNotFoundException $e) {
            self::dispatchAlert(DispatchAlertTypeEnum::ERROR,'Error reading news category: ' . $e->getMessage(), $this->pageTitle);
        }
        $this->form->setNewsCategory($newsCategory, $this->isEdit);
    }

    public function update(Request $request)
    {
        ...
    } // public function update()



    public function cancel()
    {
        $this->redirect(route('admin.newsCategories.index'), navigate: true);
    }

}

Я использую форму app/Livewire/Forms/NewsCategoryForm.php:

namespace App\Livewire\Forms;

use App\Models\NewsCategory;
use Livewire\Form;

class NewsCategoryForm extends Form
{
    public NewsCategory $newsCategory;
    public $id;
    public $name;
    public $description;
    ...
    public bool $isEdit = false;

    public function setNewsCategory(NewsCategory $newsCategory, bool $isEdit)
    {
        $this->newsCategory = $newsCategory;
        $this->name = $newsCategory->name;
        $this->description = $newsCategory->description;
        ...
        $this->isEdit = $isEdit;
    }

    public function getNewsCategory(): NewsCategory
    {
        $this->newsCategory->name = $this->name;
        $this->newsCategory->description = $this->description;
        ...
        return $this->newsCategory;
    }

    public function setDescription(string $description)
    {
        $this->description = $description;
    }


}

и шаблон лезвия:

<div class = "editor_form_wrapper">

    <form class = "form-editor" @if ($form->isEdit)  wire:submit = "update"
          @else  wire:submit = "store" @endif enctype = "multipart/form-data">

        @include('admin.validation_errors', ['show_error_items' => true])

        @if ($form->isEdit)
            <div class = "editor_field_block_wrapper">
                <div class = "editor_field_block_device_splitter">
                    <div class = "w-4/12 pb-0 pl-2 md:pt-3">
                        <label for = "id" class = "editor_field_block_device_label">Id: </label>
                    </div>
                    <div class = "p-2 w-full">
                        <input id = "id" name = "id" type = "text" class = "editor_form_readonly" value = "{{ $form->id }}"
                               tabindex = "-1" readonly/>
                    </div>
                </div>
            </div>
        @endif


        <div class = "editor_field_block_wrapper">
            <div class = "editor_field_block_device_splitter">
                <div class = "w-4/12 pb-0 pl-2 md:pt-3 ">
                    <label for = "name" class = "editor_field_block_device_label">Name: <span
                            class = "editor_form_aria_required" aria-required = "true"> * </span></label>
                </div>
                <div class = "p-2 w-full">
                    <input id = "name" type = "text"
                           class = "editor_form_input"
                           maxlength = "50"
                           wire:model = "form.name"
                           autocomplete = "off"
                           placeholder = "Fill string describing news category"
                           tabindex = "10"
                           autofocus/>
                    @error('form.name')
                    <span class = "error_text">{{$message}}</span>
                    @enderror
                </div>
            </div>
        </div>


        <div class = "editor_field_block_wrapper">
            <div class = "editor_field_block_device_splitter">
                <div class = "w-4/12 pb-0 pl-2 md:pt-3">
                    <label for = "description" class = "editor_field_block_device_label">Description: <span
                            class = "editor_form_aria_required" aria-required = "true"> * </span> </label>
                </div>
                <div class = "px-2 w-full">
                    <textarea wire:model = "form.description"
                              class = "min-h-fit h-48 " rows = "4" cols = "80"
                              name = "description"
                              id = "description">{{ $form->description }}</textarea>
                    <div>
                        <span class = "text-lg">You typed:</span>
                        <div class = "w-full min-h-fit h-48 border border-gray-200">{{ $form->description }}</div>
                    </div>

                </div>
                @error('form.description')
                <span class = "error_text">{{$message}}</span>
                @enderror
            </div>
        </div>


        ...
          
        @if ($form->isEdit)
            <div class = "editor_field_block_wrapper">
                <div class = "editor_field_block_device_splitter">
                    <div class = "w-4/12 pb-0 pl-2 md:pt-3 ">
                        <label for = "created_at" class = "editor_field_block_device_label">Created at</label>
                    </div>
                    <div class = "p-2 w-full">
                        <input
                            id = "created_at" name = "created_at" type = "text"
                            class = "editor_form_readonly"
                            value = "{{ $form->created_at }}"
                            tabindex = "-1"
                            readonly/>
                    </div>
                </div>
            </div>

            @if (!blank($form->updated_at))
                <div class = "editor_field_block_wrapper">
                    <div class = "editor_field_block_device_splitter">
                        <div class = "w-4/12 pb-0 pl-2 md:pt-3 ">
                            <label for = "updated_at" class = "editor_field_block_device_label">Updated at</label>
                        </div>
                        <div class = "p-2 w-full">
                            <input
                                id = "updated_at" name = "updated_at" type = "text"
                                class = "editor_form_readonly"
                                value = "{{ $form->updated_at }}"
                                tabindex = "-1"
                                readonly/>
                        </div>
                    </div>
                </div>
            @endif
        @endif

        <div class = "flex items-center justify-end p-2 text-right sm:px-6">
            <div class = "mb-3 flex justify-between">
                <button class = "btn_editor_form_cancel" wire:click = "cancel">
                    Cancel
                </button>

                <button class = "btn_editor_form_submit" type = "submit">
                    Edit 
                </button>
            </div>
        </div>

    </form>

</div>





    <script>
        ClassicEditor
            .create(document.querySelector('#description'))
            .then(editor => {
                editor.model.document.on('change:data', () => {
                    console.info('editor.getData()::')
                    console.info(editor.getData())

                @this.set('form.description', editor.getData());
                })
            })
            .catch(error => {
                console.error(error);
            });
    </script>

Есть идеи, что не так в моем коде и как это исправить?

🤔 А знаете ли вы, что...
Laravel активно обновляется и совершенствуется, чтобы соответствовать современным стандартам.


1
74
1

Ответ:

Решено

Похоже, что в представлении вы забыли заключить <textarea> с помощью провода:игнорировать, как показано в исходном фрагменте кода, поэтому, когда Livewire обновляет DOM, также перезаписывает текстовую область, и ClassicEditor теряет свои ссылки.

НО в этом конкретном виде, по причине, которую я еще не смог выяснить, есть элемент, вызывающий проблемы. Это:

input id = "id" name = "id" type = "text" class = "editor_form_readonly" value = "{{ $form-> id }}" tabindex = "-1" readonly />

При попытке переименовать идентификатор и имя (например, id = "_id" name = "_id") все работает нормально. Однако имейте в виду, что без Wire:model вход также будет игнорироваться Livewire. Единственное, о чем я могу думать, это то, что в Livewire есть механизм, который предотвращает изменение столбца id модели, но я не уверен, имеет ли это отношение к этому случаю...

Предложение: поскольку @this.set() выполняет ajax-вызов каждый раз, когда вы вводите символ, я рекомендую изменить его следующим образом:

editor.model.document.on('change:data', () => {

   @this.form.description = editor.getData(); // <~~~ THIS
})

таким образом изменения сохраняются локально и могут быть отправлены на сервер при отправке формы.

Если вы хотите, в целях отладки в представление можно добавить кнопку, выполняющую обновление:

<button type = "button" wire:click = "$refresh">
    Refresh
</button>

Кроме того, поскольку вы напечатали начальное значение текстовой области в HTML, вы можете удалить из нее wire:model = "form.description", поскольку это свойство обрабатывается @this.form.description = editor.getData()