Livewire and CKEditor - laravel

I'm trying to use some ritch text editors with livewire. I've used code from here
https://laracasts.com/discuss/channels/laravel/how-to-bind-ckeditor-value-to-laravel-livewire-component
but it gets error in console
CKEditorError: this.viewElement.ownerDocument.body is null
My code:
<div
class="form-textarea w-full"
x-data
x-init="
console.log($refs.myIdentifierHere)
ClassicEditor.create($refs.myIdentifierHere)
.then( function(editor){
editor.model.document.on('change:data', () => {
$dispatch('input', editor.getData())
})
})
.catch( error => {
console.error( error );
} );
"
wire:ignore
wire:key="myIdentifierHere"
x-ref="myIdentifierHere"
wire:model.debounce.9999999ms="description">{!! $description !!}</div>

I have this error too. I've narrowed it down though such that I only have it happen when the ckeditor component is inside of an alpinejs element using x-show to hide it. (I have a form with tabs across the top to switch between the many inputs).
Outside of an alpinejs component, my ckeditor component, which looks identical to yours except for id's, works fine with livewire.

Related

Quasar2 Vue3 Cypress multi-select test fails with strange error

My template:
<template>
<q-item tag="label" v-ripple>
<q-select
borderless
stack-label
emit-value
map-options
multiple
class="full-width"
v-model="model"
:options="options"
:label="name"
>
<template v-slot:after>
<q-btn
data-test="btnMultipleDropDownSetting"
round
dense
flat
color="primary"
icon="done"
#click="multiSelectionCompletes"
:disable="submitButtonDisable"
/>
</template>
</q-select>
</q-item>
</template>
Test code:
it('Verify Multiple-Select from auto-generated page', () => {
cy.get('[data-test="multidropdown-setting-4"]').find('label').should('contain', "Auto Generated Multi-Selection box");
cy.get('[data-test="multidropdown-setting-4"]').find('label').click();
cy.get('[data-test="multidropdown-setting-4"]').find('label').select(["Option 1"]);
cy.get('body').click();
cy.get('[data-test="multidropdown-setting-4"]').find('span').should('have.text', 'Option 1');
}); // XXX
Cypress fails with very strange error without even running the test yet:
The Quasar Cypress helpers overrides the .select(), see cypress.overrides.ts
if (subject.hasClass('q-select')) {
if (Array.isArray(valueOrTextOrIndex)) {
if (!subject.hasClass('q-select--multiple')) {
throw new Error(
'Cypress: select command with array param can only be used with a multiple select',
);
}
} else {
valueOrTextOrIndex = [valueOrTextOrIndex];
}
This shows that the
<q-select
...
multiple
>
should throw an error (not the one you get, but the one shown above) when you pass a single value into the .select().
Try passing an array
cy.get('[data-test="multidropdown-setting-4"]')
.find('label')
.select(["Option 1"])
BTW The error message you get above isn't coming from the .select() override, but from the portal helper. I haven't traced back to that point, but try with the above mod first as it seems most likely.
Using cy.withinSelectMenu()
This might also work:
cy.get('[data-test="multidropdown-setting-4"]')
.find('label')
.click(); // open the menu
cy.withinSelectMenu( // should only be one menu open
{persistent: true}, // this means you have a multiple select
() => {
cy.get('.q-item[role=option]').contains("Option 1").click();
})
I was facing the same issue. Got it to work by going through the quasar testing Github repo. Sample Code if anyone is facing similar issue.
cy.dataCy('select').click()
cy.withinSelectMenu({
persistent: true,
fn: () => {
cy.contains('Option One').click()
},
})

laravel livewire breaks styling (#push script)

I applied livewire on top of an already made laravel project.
It's simply applying wire:model to select like below.
<select wire:model="wired" id="#selector-01" >
<option>1</option>
<option>1</option>
</select>
and using the wire variable(wired) in if statement in for loop.
<select id="#selector-02">
#foreach($numbers in $number)
#if($some_id == $wired)
<option> some_id </option>
#endif
#endforeach
</select>
I use it only as a component.
all the data is controlled in the original laravel controller.
livewire component is called by #livewire('component-name')
and everything works, as I thought it would, except styling.
I think it has to do with using SlimSelect
At the end of livewire component-name.blade.php, I have SlimSelect styling just like the below.
#push('js')
<script>
new SlimSelect({
select: '#selector-01'
})
new SlimSelect({
select: '#selector-02'
})
</script>
#endpush
I tried moving the codes to
original.blade.php with #push and #stack
app.blade.php without #push
but still styling breaks.
I am thinking a solution might be adding few lines in update() in live wire controller to reinject the styling script.
am I going in the right direction?
Please help.
adding the below code fixed the problem.
<script>
document.addEventListener('livewire:update', function () {
// Your JS here.
new SlimSelect({
select: '#selector-01'
})
new SlimSelect({
select: '#selector-01'
})
})
</script>
you can also use livewire:onload instead of #stack and #push for loading styling onload
Reference to livewire doc

Get Data back from Vue Component

Is it possible to get Data back from a vue component?
Laravel blade.php code:
...
<div>
<component1></component1>
</div>
...
In component1 is a selectbox which i need (only the selected item/value) in the blade.php
A vue component, when rendered in the browser, is still valid HTML. If you make sure your component is wrapped in a form element and has a valid input element, and the form can be submitted, the PHP endpoint can consume the form’s data without problems. It could look like this:
Layout/view:
<form method="post" action="/blade.php">
<component1></component1>
<button type="submit">Submit form</button>
</form>
Component (<component1/>):
<fieldset>
<input type="checkbox" name="my_option" id="my_option">
<label for="my_option">I have checked this checkbox</label>
</fieldset>
PHP script (blade.php):
echo $_POST["my_option"] // if checked, should print "on"
If you are looking for a JavaScript centered approach, you may want to serialize the form and fetch the endpoint; it could look similar to this:
import serialize from 'form-serialize';
const formData = serialize(form)
fetch(form.action, { method: 'POST' }, body: JSON.stringify(formData) })
.then(response => {
// update page with happy flow
})
.catch(error => {
// update page with unhappy flow
})
Building from an accessible and standardized basis using proper HTML semantics will likely lead to more understandable code and easier enhancements down the road. Good luck!
(Edit: if you require a complete, working solution to your question, you should post more code, both from the Vue app as well as the PHP script.)

How can i make progress bar for livewire function execution in laravel

I Want Make a Progress Bar For My Live Wire Function Progress.
When i Use wire:loading i can just show spinning icon o another text like "uploading ..." , now how can i make progress bar for that ?
I was found it in live wire documentation but not work for show function execution :
<script>
document.addEventListener('livewire:load',() => {
let progressSection = document.querySelector('#progressbar'),
progressBar = progressSection.querySelector('#progress-fill');
document.addEventListener('livewire-upload-start' , () => {});
document.addEventListener('livewire-upload-finish' , () => {});
document.addEventListener('livewire-upload-error' , () => {});
document.addEventListener('livewire-upload-progress' , (event) => {
progressSection.style.display = "block";
console.log(`${event.detail.progress}%`);
progressBar.style.width = `${event.detail.progress}%`;
});
});
</script>
in the live wire component i was upload file to my ftp server and i want show uploading percentage of file in front end , when i run the upload method.
thanks very much
I had to use Alpine as well for show/hide purpose and plus it binds well with livewire.
Below is an example for uploading resume.
<form wire:submit.prevent="uploadResume">
<div x-data="{ isUploading: false, progress: 0 }"
x-on:livewire-upload-start="isUploading = true"
x-on:livewire-upload-finish="isUploading = false"
x-on:livewire-upload-error="isUploading = false"
x-on:livewire-upload-progress="progress = $event.detail.progress">
<input type="file" id="resume" wire:model="resume" aria-label="Resume" />
<div class="mt-2" x-show="isUploading">
<progress max="100" x-bind:value="progress"></progress>
</div>
</div>
</form>
use Livewire\WithFileUploads;
class Upload extends Component
{
use WithFileUploads;
public function uploadResume()
{
// upon form submit, this function till fill your progress bar
}
}

Can I use CKEditor 5 Inline or Balloon Editor on a form submission?

I'd like to use the CKEditor 5 Inline or Balloon editor on a form submission, but I'm having difficulty.
I can get the submission to work perfectly w/ Classic Editor but the Inline Editor prevents me from typing in the field.
Here is my code:
<script type="text/javascript">
InlineEditor.create( document.querySelector( '#ck' ) );
</script>
Here is the HTML:
<div class="form-group">
<label>Comment</label>
<textarea cols="80" rows="10" name="comment" class="form-control" id="ck">foo
</div>
On the page, the editor shows up, but I am unable to type into it on Safari (Mac).
I looks like this was possible in CKEditor 4, it is possible in 5?
Unfortunately, InlineEditor and BalloonEditor are not meant to replace <textarea> element. ClassicEditor works in this case because it just replaces the whole element with its own containers, but this is not the case for other editors.
CKEditor 4 was kind of one solution to suit all the needs. There were a lot of things happening under the hood. With CKEditor 5 we give you builds and an API, but the integration needs to be done by the outside developer. I am not saying this will never change, although this is the status for now.
Additionally, at the moment, neither editor will replace <textarea> value as you type.
If you want to use ClassicEditor, you might want to replace <textarea>'s value with editor data on form submission.
const textarea = document.querySelector( '#ck' );
ClassicEditor
.create( textarea )
.then( editor => { window.editor = editor } );
document.getElementById( 'submit' ).onclick = () => {
textarea.value = editor.getData();
}
If you would like to use InlineEditor or BalloonEditor, you need to use <div> instead of <textarea>. You could create a hidden input field and set its value to editor data in a similar fashion as above.

Resources