Use SortableJS/Vue.Draggable with Laravel Livewire - laravel

I’m building a Livewire component for a table. I want the rows to be sortable, so I’m trying to implement VueDraggable inside my Livewire component.
On my LivewireTable component, I define one public property called $records.
On the view, I’m using vue-draggable like so:
<vue-draggable wire:model="records" tag="tbody">
#foreach($records as $record)
<tr>
(...)
</tr>
#endforeach
</vue-draggable>
When I inspect the Vue component the value is null, which means Livewire is not doing what it‘s supposed to.
I’m sure I’m doing something wrong. Can anyone help? Thanks in advance.

The Vue JS support was abstracted out in a separate package. You can find it at https://github.com/livewire/vue

Related

Livewire and getting the element id from wire:id

I'm using a livewire full-page component to display a list of tasks along with all the CRUD stuff associated, and using dragula to allow for drag and drop.
I initially had all this running through a TaskListComponent, and was having trouble getting some of the functionality to work so I now have a child component that just handles the task itself. So there's a TaskListComponent that's the page, and and then I have a TaskComponent that's added to the page in a foreach loop. my thought is that all the task list type functionality would happen in the main component, and anything related to the specific task (show, update, delete, etc) would be in the TaskComponent. Tell me if that's how you would structure it?
My question now is, based on that structure, I have some javascript that's running on the page to listen for the dragula drop event and handle reordering/changing status of tasks and it relies on the element ID, but since I made each task a livewire component now the element id is being replaced with wire:id which is some hash value. I don't know how to access that in javascript and get the original html element ID.
This is what's in my blade file:
#foreach ($tasks as $task)
#if ($task->task_status_id === $status->id)
<livewire:tasks.task-component wire:key="{{ $task->id }}" :task="$task" data-task-id="{{ $task->id }}" />
#endif
#endforeach
And here's the bit of js using dragula:
drag.on('drop', function(el, target, source, sibling) {
console.log(el);
});
The above console.log outputs:
<div wire:id="1pPdyV6eX8kgtePfXBzk" ...></div>
Sorry I know this is a noob question, but it's not clear from the docs how to get to what I'm after. I've tried using Livewire.find() but it returns undefined. I can use Livewire command in the console, so I know it's available.
Also possibly related, any kind of $wire command I call says $wire is undefined. I've got this in my app.js file that's loaded after livewire scripts:
import Alpine from 'alpinejs'
window.Alpine = Alpine
Alpine.start()
And I can do Alpine in the console and it knows what that is.
Any help would be greatly appreciated.
You should load your app.js file in the head of your document with a defer attribute.
You can then use $wire or this.$wire to access to the Livewire component. This only works when your Alpine component is inside of a Livewire component though.

VueJS v-for in laravel blade

How can I create a list in laravel (v7) blade using the VueJS v-for method?
inside home.blade.php:
<template v-for="(item,index) in this.list">
<qm-item number="#{{index}}"></qm-item>
</template>
in the source code this results in:
<qm-item number="index"></qm-item>
but i would like to have number=0 or =1 on the first qm-item, number=2 on the second and so on.
UPDATE: the issue was how I was checking it, since the DOM is re-rendered I cannot check in the browser source code for this, because this won't be up to date.
You should bind the number as follows:
<qm-item :number="index"></qm-item>
You need to bind number:
<template v-for="(item,index) in this.list">
<qm-item :number="index"></qm-item>
</template>
index will be defined on the Vue.js side, not on the Laravel side.
When you pass data from blade to your Vue component you have to bind the props with a leading :
So, in your case, it should be <qm-item :number="{{index}}"></qm-item>
Also, use variable just like you normally do in the blade.

Add variable to form action in Laravel Vue Component

How can I add a variable to the form action in Laravel Vue Component?
<form method="POST" action="/thoughtjournal/{{id}}/update">
First, you might want to use Vue models and Axios to submit your form from Vue. It's kind of one of the magical parts of working with Vue.
However, to answer your question you need to bind the action attribute using js, so you need to create a variable in the Vue's data array of id and then use the following:
<form method="POST" :action="'/thoughtjournal/' + id + '/update'">
Again, tough, that is very much not how you should be working in vue. Instead you should use v-model biding to build up/edit the thought journal model, then post or patch it using axios.

How to enhance an existing Laravel project with VueJS?

I just finished my project using only the Laravel framework. Now I want to add vue.js into my project to render the views without loading them. I went through some tutorials and found that I need to convert my blade files into Vue components to achieve this. But as I know it's a big process as some of the functions won't work in VueJS. And I don't know how to do it. Please, someone, guide me here on how to do that. Thanks in advance.
Rebuild your basic structure into a Vue template:
// MyTemplate.vue
<template>
<div> <!-- keep this single "parent" div in your template -->
<!-- your Blade layout here -->
</div>
</template>
<script>
export default {
props: [ 'data' ]
}
</script>
Add your Vue template as a global component in app.js:
// app.js
import Vue from 'vue';
window.Vue = Vue;
Vue.component('my-template', require('./MyTemplate.vue').default);
const app = new Vue({
el: '#app'
});
Use this new Vue template in your Blade template as below:
<my-template :data="{{ $onePhpVarThatHoldsAllYourData }}"></my-template>
Once inside the Vue template, you will not be able to reach back to your Laravel methods (e.g. #auth) or for additional data without an Ajax request, so make sure you package all the data you need in your Vue template up front. All of the data you send in will be prefixed inside the Vue template with the name of the prop you assign it to, in this case data.
Note, once you get more familiar with Vue you will likely start segregating the individual data values being passed to your template. For that, you will need to specify additional props in the props array in step 1, e.g.
props: ['a', 'b', 'c'],
and then individually pass their values with
<my-template :a="{{ $a }}" :b="{{ $b }}" :c="{{ $c }}"></my-template>
Convert your Blade directives to Vue directives:
Loops (e.g. #foreach) to v-fors:
#foreach ($items as $item)
<li>{{ $item }}</li>
#endforeach
becomes
<li v-for="item in data.items">{{ item }}</li>
Control structures (e.g. #if ($something !== $somethingElse) ... #endif) to v-ifs:
<div v-if="data.something !== data.somethingElse">
...
</div>
In general, as it was already mentioned in comments, there's no short way for converting your application from blades to VueJS components. Anyway, if you consider migrating to VueJS, I'd recommend you to make a full migration instead of partially using Vue components.
The main idea of migration to VueJS is to transfer all logic that you did in blade templates (like foreach's, if's etc) to Vue components and fetch all data using AJAX requests (e.g. with help of axios or nativelly).
In this case, your controllers should return all data needed for page rendering and Vue components will take care of rest rendering logic.
Also, it's a good option to use vue-router to handle rounding and make your application behave as SPA. In this case, you should create one wildcard route in your application that will return only one blade template. Inside of this template you should insert root tag that will initiate VueJS. The rest will be on the VueJS side.
If you are planning to migrate the whole application then start with authentication.
Part #1: https://codebriefly.com/laravel-jwt-authentication-vue-ja-spa-part-1/
Part #2 https://codebriefly.com/laravel-jwt-authentication-vue-js-spa-part-2/
This tutorial helped me in the past to getting started. After that split your code into components.
If you want to learn basics first then you can go with this tutorial I found this useful.
https://www.youtube.com/playlist?list=PL4cUxeGkcC9gQcYgjhBoeQH7wiAyZNrYa
Hope this helps!

Issue with Vue instance in laravel [duplicate]

I want to test a simple vue.js in laravel blade system, Here is my code in test.blade.php view file:
<div id="app">
<p>{{message}}</p>
</div>
<script src="{{url('/assets/js/vue/vue.min.js')}}"></script>
<script>
new Vue({
el:'#app',
data:{
message:"hello world"
}
});
</script>
The problem is while rendering view file laravel wants to access the message as a variable or constant and because there is no any message variable passed to view I get Use of undefined constant exception. So what's the solution?
add #{{message}}
that will tell blade to ignore this.
It's not a good approach to combine the same notation for front-end and back-end. Of course, with the #, Blade can ignore.
A much cleaner idea is to extract the front-end from back-end, because Blade and Vue.js use the same notation:
Front-end with html, css en javascript (in your case Vue.js)
Back-end (in php, Laravel in your case) as REST-api with php that returns json
The big advantages:
It's more secure
It's more maintainable
It's cleaner

Resources