Storing data in multiple pivot tables in Laravel and Livewire - laravel

I am working on three tables that have two pivot tables in between. It's a workbook that has a many to many relationship with stations and the same workbook that has a many to many with clients. Right now I have a page where you can save a new workbook and you can select all the stations that should be related to it and also the client that should be associated with that workbook.
I figured I would only need to use the store in workbook since that would be the table that connects them both.
public function store(StoreWorkbookRequest $request)
{
$workbook = Workbook::create($request->only('wrkb_name'));
$workbook->stations()->sync($request->input('stations', []));
$workbook->clients()->sync($request->input('clients', []));
return redirect()->route('admin.workbooks.create')->with('success', 'Successfully Created a New Workbook');
}
I am also using livewire and I have the form for create in a livewire component.
<form action="{{route('admin.workbooks.store')}}" method="POST" enctype="multipart/form-data">
#csrf
<div class="form-group">
<label for="">Workbook Name</label>
<input type="text" class="form-control" name="wrkb_name">
</div>
<table class="table-auto w-full mb-6">
<thead>
<tr>
<th class="px-4 py-2"></th>
#if($showRate)
<th wire:click="sortBy('SFM_rate')" style="cursor: pointer;" class="px-4 py-2">SFM Rate #include('partials.sort-icon',['field'=>'SFM_rate'])</th>
#endif
#if($showLetter)
<th wire:click="sortBy('call_letter')" style="cursor: pointer;" class="px-4 py-2">Call Letter #include('partials.sort-icon',['field'=>'call_letter'])</th>
#endif
</tr>
</thead>
<tbody>
#foreach($stations as $key => $station)
<tr>
<td class="border px-4 py-2">
<input wire:model="selected" value="{{ $station->id }}" type="checkbox">
</td>
#if($showRate)
<td class="border px-4 py-2">{{$station->SFM_rate}}</td>
#endif
#if($showLetter)
<td class="border px-4 py-2">{{$station->call_letter}}</td>
#endif
</tr>
#endforeach
</tbody>
</table>
{!! $stations->links() !!}
#else
<p class="text-center"> No stations were found</p>
#endif
<div class="w-full flex pb-10" >
<div class="w-1/6 relative mx-1">
<select wire:model="clientselected" class="block appearance-none w-full bg-gray-200 border border-gray-200 text-gray-700 py-3 px-4 pr-8 rounded leading-tight focus:outline-none focus:bg-white focus:border-gray-500" id="grid-state">
<option value="" >Select a Client</option>
#foreach($clients as $id => $client)
<option value="{{ $id }}">{{ $client->name }}</option>
#endforeach
</select>
</div>
<div class="w-1/6 relative mx-1 space-x-6">
<button class="block appearance-none w-full bg-black border border-gray-200 text-white py-3 px-4 pr-8 rounded leading-tight focus:outline-none focus:bg-white focus:border-gray-500">Create Workbook</button>
</div>
</div>
</form>
When I submit the form only the workbook is created and the two pivot tables remain unchanged.

I got it to work. I added in my selectors the name="stations[]" and name="clients[]"
<input name="stations[]" wire:model="selected" value="{{ $station->id }}" type="checkbox">
<select name="clients[]" wire:model="clientselected" class="block appearance-none w-full bg-gray-200 border border-gray-200 text-gray-700 py-3 px-4 pr-8 rounded leading-tight focus:outline-none focus:bg-white focus:border-gray-500" id="grid-state">
Now all the data is getting sent.

Related

Why is my Laravel date column displaying a time as well?

I am developing a prototype in Laravel 9 which currently contains 7 user tables. Several of those tables contain dates and all of them are defined as Laravel dates; they are all defined as MySQL dates in the database as well. I can't figure out why one of those date columns displays all its dates as a regular date, followed by a blank and then a time - 00:00:00 - whenever displayed in my blade templates. All of the other date columns display as a date (YYYY-MM-DD) without a time.
I am NOT requesting that a time (which is always 00:00:00/midnight) be shown in that column. Why is Laravel doing this and how can I make it stop?
I realize that I can suppress the time by appending ->format('Y-m-d') but I shouldn't have to do that in the first place; if I only store a date rather that a DateTime or Timestamp, there should only be a date in the column and no need to suppress the time to keep it from displaying.
UPDATE
Here is the migration for the table that is giving me trouble:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('non_driving_weekdays', function (Blueprint $table) {
$table->date('non_driving_weekday_date');
$table->string('reason', 50);
$table->timestamps();
$table->primary('non_driving_weekday_date', 'non_driving_weekday_date_PK');
$table->foreign('reason', 'reason_FK')->references('reason_for_not_driving')->on('non_driving_reasons')->onUpdate('cascade')->onDelete('restrict');
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('non_driving_weekdays');
}
};
Here is the blade that displays the index:
<x-layout>
<div class="bg-gradient-to-b from-red-500 to-purple-100">
<h1 class="text-3xl text-center text-white font-bold bg-indigo-700">Non-driving Weekdays - Index</h1>
<h1 class="pb-5"></h1><!-- spacer beneath title -->
#if (session()->has('message'))
<div id="message"
x-data="{show: true}"
x-init="setTimeout(() => show = false, 5000)"
x-show="show"
class="w-1/3 mx-auto text-center text-black bg-yellow-300 rounded-md">
<p class="text-xl py-1">{{session('message')}}</p>
</div>
#endif
<div class="flex justify-center h-screen" style="display: grid; grid-template-rows: auto auto auto auto; row-gap: 10px; padding: 10px">
<table><tr><td><img src="{{asset('icons/green-plus-circle-outline.svg')}}" width="50" alt="add icon"></td><td class="font-bold">Add a new date where the drivers didn't drive</td></tr></table>
{{-- If there are no non-driving weekdays, indicate that to the user. --}}
#if (count($nonDrivingWeekdays) == 0)
<p>No non-driving weekdays found.</p>
#else
{{-- If there are non-driving weekdays, display them. --}}
<div>
<table class="border-black border-2 bg-white">
<thead class="border-black border-2 text-white bg-gray-800">
<tr class="content-center">
<th class="border-black border-2 p-2 text-left">Date</th>
<th class="border-black border-2 p-2 text-left">Reason</th>
<th class="border-black border-2 p-2">View</th>
<th class="border-black border-2 p-2">Edit</th>
<th class="border-black border-2 p-2">Delete</th></tr>
</thead>
<tbody class="border-black border-2">
#foreach($nonDrivingWeekdays as $nonDrivingWeekday)
<tr class="border-black border-2">
{{-- ->format('Y-m-d') --}}
<td class="border-black border-2 p-2">{{$nonDrivingWeekday->non_driving_weekday_date}}</td>
<td class="border-black border-2 p-2">{{$nonDrivingWeekday->reason}}</td>
<td class="border-black border-2 p-2 text-center"><img src="{{asset('icons/magenta-details.svg')}}" width="25" alt="view icon"></td>
<td class="border-black border-2 p-2 text-center"><img src="{{asset('icons/yellow-lead-pencil.svg')}}" width="25" alt="update icon"></td>
<td class="border-black border-2 p-2 text-center">
<form method="POST" action="/nonDrivingWeekdays/destroy/{{$nonDrivingWeekday->non_driving_weekday_date}}">
#csrf
#method('DELETE')
<button><img src="{{asset('icons/red-delete.svg')}}" width="25" alt="delete icon"></button>
</form></td>
</td>
</tr>
#endforeach
</tbody>
</table>
</div>
#endif
<div>
<p class="mt-6 p-4">{{$nonDrivingWeekdays->links()}}</p>
</div>
</div>
</div>
</x-layout>
This is the blade for the show() method:
<x-layout>
{{-- <x-card class="p-10"> --}}
<div class="bg-gradient-to-b from-purple-500 to-purple-100 h-screen">
<h1 class="text-3xl text-center text-white font-bold bg-indigo-700">Non-driving Weekdays - Show One Weekday</h1>
<h1 class="pb-5"></h1><!-- spacer beneath title -->
<form method="GET" enctype="multipart/form-data" class="w-4/5 mx-auto">
<div class="mb-6">
<label for="non_driving_weekday_date" class="inline-block text-lg mb-2">Reason</label>
<input type="text" disabled class="border border-gray-200 rounded p-2 w-full" name="non_driving_weekday_date" value="{{$nonDrivingWeekday->non_driving_weekday_date}}"/>
</div>
<div class="mb-6">
<label for="reason" class="inline-block text-lg mb-2">Reason</label>
<input type="text" disabled class="border border-gray-200 rounded p-2 w-full" name="reason" value="{{$nonDrivingWeekday->reason}}"/>
</div>
<div class="mb-6">
{{-- Cancel submission of the form --}}
<button type="button" class="text-xl text-white bg-black rounded-md py-2 px-4 hover:bg-white hover:text-black hover:outline hover:outline-2 hover:outline-black">Cancel</button>
</div>
</form>
{{-- </x-card> --}}
</div>
</x-layout>
And this is the blade template for the edit() method:
<x-layout>
{{-- <x-card xclass="p-10 max-w-lg mx-auto mt-24"> --}}
<div class="bg-gradient-to-b from-yellow-500 to-yellow-100 h-screen">
<h1 class="text-3xl text-center text-white font-bold bg-indigo-700">Non-driving Weekdays - Edit One Weekday</h1>
<h1 class="pb-5"></h1><!-- spacer beneath title -->
<form method="POST" action="/nonDrivingWeekdays/update/{{$nonDrivingWeekday->non_driving_weekday_date}}" enctype="multipart/form-data" class="w-4/5 mx-auto">
#csrf
#method('PUT')
<div class="mb-6">
<label for="non_driving_weekday_date" class="inline-block text-lg mb-2">Non-driving weekday date</label>
<input type="text" class="border border-gray-200 rounded p-2 w-full" name="non_driving_weekday_date" value="{{$nonDrivingWeekday->non_driving_weekday_date}}"/>
#error('non_driving_weekday_date')
<p class="text-red-500 font-bold text-m mt-1">{{$message}}</p>
#enderror
</div>
<div class="mb-6">
<label for="reason" class="inline-block text-lg mb-2">Reason</label>
<select id="reason" name="reason" class="h-10">
#foreach($reasons as $reason)
#if($reason->reason_for_not_driving === $nonDrivingWeekday->reason)
<option selected class="mx-10" value="{{$reason->reason_for_not_driving}}">{{$reason->reason_for_not_driving}}</option>
#else
<option class="mx-10" value="{{$reason->reason_for_not_driving}}">{{$reason->reason_for_not_driving}}</option>
#endif
#endforeach
</select>
</div>
<div class="mb-6">
{{-- Submit the completed form --}}
<button class="text-xl text-white bg-orange-500 rounded-md py-2 px-4 hover:bg-white hover:text-orange-500 hover:outline hover:outline-2 hover:outline-orange-500">Submit</button>
{{-- Cancel submission of the form --}}
<button type="button" class="text-xl text-white bg-black rounded-md py-2 px-4 hover:bg-white hover:text-black hover:outline hover:outline-2 hover:outline-black">Cancel</button>
</div>
</form>
{{-- </x-card> --}}
</div>
</x-layout>
Lastly, here is the model:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class NonDrivingWeekdays extends Model
{
use HasFactory;
protected $fillable = ['non_driving_weekday_date', 'reason'];
protected $primaryKey = 'non_driving_weekday_date';
protected $keyType = 'date';
public $incrementing = 'false';
}
StewieSWS gave me the clue that helped me solve this: I wasn't displaying the dates in form fields that were <input type="date">. Frankly, I'd forgotten there was a special input type for dates! In the blade for my index() method, I was displaying the data as a cell in a table and in the blades for the edit(), show() and create() methods, I was displaying them in <input type="text"> fields. As soon as I started displaying the dates in <input type="date"> fields, they started displaying as normal dates WITHOUT any time component. I even got a little calendar icon at the right end of the box which lets me pick a date from calendar. As an added bonus, I even got some additional validating: when I tried to enter an impossible date, Feb 30, 2023, the input field detected it and displayed an appropriate message.

I started a project with laravel, vuejs, inertia js and jetstream. but I have a problem with my form I can't get all the data

I started a project with laravel, vuejs, inertia js and jetstream. but I have a problem with my form I can't get all the data from the form, here is the code of my component invoice.vue.
<script setup>
import AppLayout from '#/Layouts/AppLayout.vue';
import { ref} from 'vue';
import { reactive } from 'vue';
import {Inertia } from "#inertiajs/inertia";
const showLine = ref([false])
let item = ref([])
let listCart = ref([])
const addCart = (item) => {
const itemCart = {
id: item.id,
unite: item.unite,
pu: item.pu,
designation: item.designation,
qte : item.qte
}
listCart.value.push(itemCart)
}
const removeItem = (i) => {
listCart.value.splice(i,1)
}
const Total = () => {
let total = 0
listCart.value.map((data) => {
total = total + ((data.qte)* (data.put) );
})
return total
}
let content = Total();
let itemCart = reactive({
unite:'',
pu:'',
designation:'',
qte:''
});
let form = reactive({
grand_total: content ,
reference: '',
intitule: '',
name: '',
date: '',
address: '',
destinataire: '',
terms_and_conditions: '',
});
let submit = () => {
Inertia.post('invoice', form);
};
</script>
<template>
<AppLayout title="Invoice ">
<main class="flex-1 overflow-x-hidden overflow-y-auto bg-gray-200">
<div class="container sm:mx-96 px-0 py-12">
<h3 class="text-3xl font-medium text-gray-700">
Nouvelle facture
</h3>
<div class="mt-4">
</div>
<div class="mt-8"></div>
<div class="flex flex-col-3 mt-2 ">
<div class="py-2 -my-2 overflow-x-auto sm:-mx-6 sm:px-6 lg:-mx-8 lg:px-8">
<div class="inline-block min-w-full overflow-hidden align-middle border-b border-gray-200 shadow sm:rounded-lg">
<form #submit.prevent="submit">
<table class="min-w-full ">
<tbody class="bg-white">
<tr>
<td class="px-4 py-4 border-b border-gray-200 whitespace-nowrap">
<div class="flex items-center">
<div class="ml-4">
<div class="text-sm font-medium leading-5 text-gray-900" >
<input type="text" v-model="form.name" name="nomEntreprise" placeholder="Nom de l'entreprise">
</div>
</div>
</div>
</td>
<td class=" border-b border-gray-200">
<div class="flex items-center">
<div class="ml-4">
<div class="text-sm font-medium leading-5 text-gray-900" >
<input type="text" v-model="form.address" name="adressEntreprise" placeholder="Adresse de l'entreprise">
</div>
</div>
</div>
</td>
<td class=" border-b border-gray-200 whitespace-nowrap">
<div class="flex items-center">
<div class="ml-4">
<div class="text-sm font-medium leading-5 text-gray-900" >
<input type="text" name="reference" v-model="form.reference" placeholder="Numéro facture">
</div>
</div>
</div>
</td>
</tr>
<tr>
<td class="px-4 py-4 border-b border-gray-200 whitespace-nowrap">
<div class="flex items-center">
<div class="ml-4">
<div class="text-sm font-medium leading-5 text-gray-900" >
<input type="Date" name="Date" v-model="form.date" placeholder="Date délivrance">
</div>
</div>
</div>
</td>
<td class=" border-b border-gray-200 whitespace-nowrap">
<div class="flex items-center">
<div class="ml-4">
<div class=" text-gray-900" >
<!-- <input type="text" name="Intitule" placeholder="Intitulé de la facture"> -->
<textarea name="intitule" id="" v-model="form.intitule" cols="30" placeholder="Intitulé de la facture"></textarea>
</div>
</div>
</div>
</td>
<td class=" border-b border-gray-200 whitespace-nowrap">
<div class="flex items-center">
<div class="ml-4">
<div class=" text-gray-900" >
<!-- <input type="text" name="Intitule" placeholder="Intitulé de la facture"> -->
<textarea name="destinataire" id="" v-model="form.destinataire" cols="30" placeholder="Destinataire"></textarea>
</div>
</div>
</div>
</td>
</tr>
</tbody>
</table>
<div class="mt-8"></div>
<table class="table-auto">
<thead class="border-gray-200">
<tr>
<th class="px-1 py-3 text-xl font-medium leading-4 tracking-wider text-left text-gray-500 uppercase border-b border-gray-200 bg-gray-50">Désignation</th>
<th class="px-1 py-3 text-xl font-medium leading-4 tracking-wider text-left text-gray-500 uppercase border-b border-gray-200 bg-gray-50">Unité</th>
<th class="px-1 py-3 text-xl font-medium leading-4 tracking-wider text-left text-gray-500 uppercase border-b border-gray-200 bg-gray-50">Qte</th>
<th class="px-1 py-3 text-xl font-medium leading-4 tracking-wider text-left text-gray-500 uppercase border-b border-gray-200 bg-gray-50">PU</th>
<th class="px-1 py-3 text-xl font-medium leading-4 tracking-wider text-left text-gray-500 uppercase border-b border-gray-200 bg-gray-50">prix total (FCFA)</th>
<th class="px-1 py-3 text-xs font-medium leading-4 tracking-wider text-left text-gray-500 uppercase border-b border-gray-200 bg-gray-50"></th>
</tr>
</thead>
<tbody>
<tr v-for="(itemCart) in listCart" :key="itemCart.id">
<td class="px-1 py-4 border-b border-gray-200 whitespace-nowrap"><textarea name="designation" v-model="itemCart.designation" placeholder="Désignation" id="" cols="20" ></textarea></td>
<td class="px-1 py-4 border-b border-gray-200 whitespace-nowrap"><input type="text" name="unite" v-model="itemCart.unite" placeholder="unité" ></td>
<td class="px-1 py-4 border-b border-gray-200 whitespace-nowrap"><input type="number" v-model="itemCart.qte" name="qte" placeholder="Qté" ></td>
<td class="px-1 py-4 border-b border-gray-200 whitespace-nowrap"><input type="number" v-model=" itemCart.pu" name="pu" placeholder="PU" ></td>
<td class="px-1 py-4 border-b text-zinc-600 font-bold border-gray-200 whitespace-nowrap"><p v-if="itemCart.qte" > {{(itemCart.qte)*(itemCart.pu)}}</p> </td>
<td class="px-1 py-4 text-xl border-b text-red-600 font-bold border-gray-200 whitespace-nowrap"><a type="button" #click="removeItem(i)"> ×</a> </td>
</tr>
<tr>
<td class="border-b border-gray-200 whitespace-nowrap"><textarea v-model="form.terms_and_conditions" name="terms_conditions" id="" cols="20" placeholder="Termes et conditions" rows="5" ></textarea></td>
</tr>
<tr>
<td><p></p></td>
<td><p></p></td>
<td><p></p></td>
<td class="border-b border-gray-200 whitespace-nowrap"><p >Total HT</p></td>
<td><p>(FCFA)</p></td>
</tr>
<tr>
<td><p></p></td>
<td><p></p></td>
<td><p></p></td>
<td class="border-b border-gray-200 whitespace-nowrap"><p>Total </p></td>
<td>
<p id="totalElements" > {{ Total() }} (FCFA)</p>
</td>
<input type="button" v-model="grand_total">
</tr>
</tbody>
</table>
<div class="mt-8"></div>
<a type="button" class="px-96 py-2 mx-24 rounded sm:inline-block bg-blue-700 font-semibold text-white " #click="addCart(item)">
Ajouter une ligne <i class="fa-solid fa-plus"></i>
</a>
<div class="mt-8"></div>
<button class="px-24 py-2 mx-96 rounded sm:inline-block bg-blue-700 font-semibold text-white"
type="submit"
>
Enregistrer
</button>
</form>
</div>
</div>
</div>
</div>
</main>
</AppLayout>
</template>
I would like to get all the data from my form but I don't know how I can do to get the data from the fields ( v-model = itemcart.description, v-model = itemcart.pu, v-model = itemcart.qte ). I tried but I can't do it.
and this is what I tried to do:
let form = reactive({
listCart:[
itemCart.designation,
itemCart.pu,
itemCart.qte,
itemCart.unite,
],
grand_total: content ,
reference: '',
intitule: '',
name: '',
date: '',
address: '',
destinataire: '',
terms_and_conditions: '',
});

Vue Laravel not showing data from method

I know I am blind because I've been looking at this for 2 days off and on and I think I am just eye stuck on what is really going on. Below is the code. What SHOULD happen is an array of data should be shown into a modal. I can see the data as "rooms" in web inspector with all the fields, but it isnt populating into the v-for - all im asking for is a little help if you can see where I screwed up
<!-- This example requires Tailwind CSS v2.0+ -->
<template>
<TransitionRoot as="template" :show="open">
<Dialog as="div" class="fixed z-10 inset-0 overflow-y-auto" #close="open = false">
<div class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
<TransitionChild as="template" enter="ease-out duration-300" enter-from="opacity-0" enter-to="opacity-100" leave="ease-in duration-200" leave-from="opacity-100" leave-to="opacity-0">
<DialogOverlay class="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" />
</TransitionChild>
<!-- This element is to trick the browser into centering the modal contents. -->
<span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">​</span>
<TransitionChild as="template" enter="ease-out duration-300" enter-from="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95" enter-to="opacity-100 translate-y-0 sm:scale-100" leave="ease-in duration-200" leave-from="opacity-100 translate-y-0 sm:scale-100" leave-to="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95">
<div class="inline-block align-bottom bg-white rounded-lg px-4 pt-5 pb-4 text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:p-6">
<button type="button" class="bg-white rounded-md text-gray-400 hover:text-gray-500 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" #click="open = false">
<div class="hidden sm:block absolute top-0 right-0 pt-4 pr-4">
<span class="sr-only">Close</span>
<XIcon class="h-6 w-6" aria-hidden="true" />
</div>
</button>
<div class="sm:flex sm:items-start">
<div class="flex flex-col">
<div class="-my-2 overflow-x-auto sm:-mx-6 lg:-mx-8">
<div class="py-2 align-middle inline-block min-w-full sm:px-6 lg:px-8">
<div class="shadow overflow-hidden border-b border-gray-200 sm:rounded-lg">
<table class="min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50">
<tr>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Room
</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Description
</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Type
</th>
<th scope="col" class="relative px-6 py-3">
<span class="sr-only">Enter</span>
</th>
</tr>
</thead>
<tbody class="bg-white divide-y divide-gray-200">
<tr v-for="room in chatRooms" :key="room.id">
<td class="px-6 py-4 whitespace-nowrap">
<div class="flex items-center">
<div class="flex-shrink-0 h-10 w-10">
<img class="h-10 w-10 rounded-full" :src="room.image" alt="" />
</div>
<div class="ml-4">
<div class="text-sm font-medium text-gray-900">
{{ room.name }}
</div>
</div>
</div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="text-sm text-gray-900">{{ room.description }}</div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full" :class="[room.is_private === 'Public' ? 'bg-green-100 text-green-800' : room.is_private === 'Private' ? 'bg-red-100 text-red-800' : '']">
{{ room.is_private }}
</span>
</td>
<td class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
Enter
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</TransitionChild>
</div>
</Dialog>
</TransitionRoot>
</template>
<script>
import { ref } from 'vue'
import { Dialog, DialogOverlay, DialogTitle, TransitionChild, TransitionRoot } from '#headlessui/vue'
import { ExclamationIcon, XIcon } from '#heroicons/vue/outline'
export default {
props: ['rooms'],
data: function () {
return {
chatRooms: [],
rooms: [],
}
},
methods: {
getRooms() {
axios.get('/chat/rooms')
.then(response => {
this.chatRooms = response.data;
})
.catch(error => {
console.log(error);
})
}
},
components: {
Dialog,
DialogOverlay,
DialogTitle,
TransitionChild,
TransitionRoot,
ExclamationIcon,
XIcon,
},
setup() {
const open = ref(true)
return {
open,
}
},
}
</script>
Try this :
Maybe this is the cause of your problem.
Add this piece of code before methods: {} and tell me :
created() {
this.getRooms();
},
The issue was not something anyone here could solve with the information provided. So I am typing this answer in a way that I hope will trigger some help to others.
When you are doing a v-for snippet, it is important to remember what data is being pulled for processing. In my case, the following line was the issue
<span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full" :class="[room.is_private === 'Public' ? 'bg-green-100 text-green-800' : room.is_private === 'Private' ? 'bg-red-100 text-red-800' : '']">
room.is_private is a boolean not the data I want to visualize. So by saying Public and Private, I was breaking the for statement. By changing them to True and False, I was able to process the v-for statement and actually get the code to load. The solution I used was as follows. Note there are 2 versions of true and false. This is because Postgres and sqlite both expect to see the response differently. I noticed this when it worked local with 'true' but pgsql on the deployment didn't work. So this Is why the code is this way
<div v-if="room.is_private === true" class="rounded-full py-1 px-2 bg-red-100 text-red-800">
<span>Private</span>
</div>
<div v-else-if="room.is_private === false" class="rounded-full py-1 px-2 bg-green-100 text-green-800">
<span>Public</span>
</div>
<div v-else-if="room.is_private === 'true'" class="rounded-full py-1 px-2 bg-red-100 text-red-800">
<span>Private</span>
</div>
<div v-else-if="room.is_private === 'false'" class="rounded-full py-1 px-2 bg-green-100 text-green-800">
<span>Public</span>
</div>
The important lesson here is to make sure you sample the data and fields before running into code making mistakes on the type of data being requested.

Make selected item current

EDIT: Full code for the 3 most likely files are found here.
https://codepen.io/arcticmedia-ryan/project/editor/ZEQwmN
I am not sure how best to explain this so please let me know if you want more. I am building a chat room app. When a person opens up the main vue, they are presented with a "Room List" - from there they can click enter and join the room. The issue is, when they click join, it opens up the tab for the room but doesnt make it active. I feel like I am just banging my head around a simple problem
There is a prop called "SelectedRoomID" that needs to be updated from "undefined" to the room that is selected from the list.
RoomList.vue
<!-- This example requires Tailwind CSS v2.0+ -->
<template>
<TransitionRoot as="template" :show="isOpen">
<Dialog as="div" class="fixed z-10 inset-0 overflow-y-auto" #close="$emit('onClose')">
<div class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
<TransitionChild as="template" enter="ease-out duration-300" enter-from="opacity-0"
enter-to="opacity-100" leave="ease-in duration-300" leave-from="opacity-100"
leave-to="opacity-0">
<DialogOverlay class="fixed inset-0 bg-gray-700 bg-opacity-75 transition-opacity"/>
</TransitionChild>
<!-- This element is to trick the browser into centering the modal contents. -->
<span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">​</span>
<TransitionChild as="template" enter="ease-out duration-300"
enter-from="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
enter-to="opacity-100 translate-y-0 sm:scale-100" leave="ease-in duration-300"
leave-from="opacity-100 translate-y-0 sm:scale-100"
leave-to="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95">
<div class="inline-block align-bottom bg-black bg-opacity-20 rounded-lg px-6 pt-5 pb-4 text-left overflow-hidden shadow-2xl transform transition-all sm:my-8 sm:align-middle sm:p-6">
<div class="sm:flex sm:items-start">
<div class="flex flex-col">
<div class="-my-2 overflow-x-auto sm:-mx-6 lg:-mx-8">
<div class="align-middle inline-block min-w-full sm:px-4 lg:px-5">
<div class="shadow overflow-hidden border-8 border-gray-800 dark:border-gray-900 sm:rounded-lg">
<table class="min-w-full divide-y divide-gray-800">
<thead class="bg-gray-800 dark:bg-gray-900">
<tr>
<th scope="col"
class="px-6 py-3 text-left text-s font-medium text-gray-50 uppercase tracking-wider">
Room
</th>
<th scope="col"
class="px-6 py-3 text-left text-s font-medium text-gray-50 uppercase tracking-wider">
Description
</th>
<th scope="col"
class="px-6 py-3 text-left text-s font-medium text-gray-50 uppercase tracking-wider">
Type
</th>
<th scope="col"
class="px-6 py-3 text-left text-s font-medium text-gray-50 uppercase tracking-wider">
Users
</th>
<th scope="col" class="relative px-6 py-3">
<button type="button"
class="bg-white rounded-md text-gray-400 hover:text-gray-500 "
#click="$emit('onClose')">
<div class="hidden sm:block absolute top-0 right-0 pt-4 pr-4">
<span class="sr-only">Close</span>
<XIcon class="top-1 right-1 absolute h-6 w-6 text-gray-50 " aria-hidden="true"/>
</div>
</button>
<span class="sr-only">Enter</span>
</th>
</tr>
</thead>
<tbody class="bg-white dark:bg-gray-800 divide-y divide-gray-300 dark:divide-gray-600">
<tr v-for="room in $store.state.rooms.rooms" :key="room.id">
<td class="px-6 py-4 whitespace-nowrap">
<div class="flex items-center">
<div class="flex-shrink-0 h-10 w-10">
<img class="h-10 w-10 rounded-full" :src="room.image"
alt=""/>
</div>
<div class="ml-4">
<div class="text-md font-medium text-gray-900 dark:text-gray-50">
{{ room.name }}
</div>
</div>
</div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="text-md text-gray-900 dark:text-gray-50">{{ room.description }}</div>
</td>
<td class="px-2 py-4 whitespace-nowrap">
<span class="px-2 inline-flex text-s leading-5 font-medium rounded-full">
<div v-if="room.is_private === true" class="rounded-full py-1 px-2 bg-red-100 text-red-800 dark:bg-red-800 dark:text-red-100">
<span>Private</span>
</div>
<div v-else-if="room.is_private === false" class="rounded-full py-1 px-2 bg-green-100 text-green-800 dark:bg-green-800 dark:text-green-100">
<span>Public</span>
</div>
<div v-else-if="room.is_private === 'true'" class="rounded-full py-1 px-2 bg-red-100 text-red-800 dark:bg-red-800 dark:text-red-100">
<span>Private</span>
</div>
<div v-else-if="room.is_private === 'false'" class="rounded-full py-1 px-2 bg-green-100 text-green-800 dark:bg-green-800 dark:text-green-100">
<span>Public</span>
</div>
</span>
</td>
<td class="px-6 py-4 whitespace-nowrap text-center">
<a class="text-md font-medium text-gray-900 dark:text-gray-50">99</a>
</td>
<td class="px-6 py-4 whitespace-nowrap text-right text-md font-medium">
<div class="flex rounded-full py-2 px-4 bg-indigo-700 hover:bg-indigo-900">
<a href="#" #click="joinRoom(room)"
class="text-white">Enter</a>
</div>
</td>
</tr>
</tbody>
</table>
<div class="bg-gray-800 dark:bg-gray-900">
<div class="flex justify-end px-4 py-3 text-left text-s font-medium text-gray-50 uppercase tracking-wider">
<span class=" px-2 pt-2 text-xs leading-5 font-semibold rounded-full">
<a href="#">
<div class="flex rounded-full py-1 px-2 bg-green-700 text-green-100 hover:bg-green-800">
<PlusIcon class="h-5 w-5"/><span class="text-sm font-bold pl-0.5">Create Room</span>
</div>
</a>
</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</TransitionChild>
</div>
</Dialog>
</TransitionRoot>
</template>
<script>
import {Dialog, DialogOverlay, DialogTitle, TransitionChild, TransitionRoot} from '#headlessui/vue'
import {ExclamationIcon, XIcon, PlusIcon} from '#heroicons/vue/outline'
import {types as RoomTypes} from "../../../Store/modules/rooms/rooms.types";
export default {
components: {
Dialog,
DialogOverlay,
DialogTitle,
TransitionChild,
TransitionRoot,
ExclamationIcon,
XIcon,
PlusIcon,
},
props: ['rooms', 'selectedRoomId'],
emits: ['onSelectRoom', 'onLeaveRoom', 'onClose'],
methods: {
joinRoom(room) {
this.$store.dispatch(RoomTypes.JOIN_ROOM, room);
this.selectedRoomId = this.room;
this.$emit('onClose');
}
},
props: {
isOpen: Boolean,
usersCount: Boolean
},
}
</script>
Main.vue
SNIPPET OF CODE
<section aria-labelledby="primary-heading"
class="dark:bg-gray-900 min-w-0 flex-1 h-full flex flex-col overflow-hidden lg:order-last">
<room-tabs :selectedRoomId="currentRoom.id" :rooms="joinedRooms"
#onSelectRoom="currentRoom = $event" #onLeaveRoom="leaveRoom($event)"/>
<message-container :messages="messages"
class="h-full pb-2 mb-2 pt-0 mt-0 shadow-md overflow-y-auto"/>
<input-box
:room="currentRoom"
v-on:messagesent="getMessages"
class="dark:bg-gray-800 px-6 pb-6 pt-4 dark:border-t-2 dark:border-gray-600 bottom-0 sticky"
/>
</section>
I know its inside methods: joinRoom that needs to change and I know its wrong where this.selectedRoomId is - I just dont know what I need to change/fix to make it turn the selected room into the active room when you click join.
Any help would be very much appreciated!
I would use mapState to effectively watch the value in the store that is being updated by this.$store.dispatch(RoomTypes.JOIN_ROOM, room);
So in a component that needs to know this value:
computed: {
...mapState(['STORE_NAME', 'STORE_VALUE']),
},
and then you should be able to use this.STORE_VALUE as a dynamically updated value

Getting my toggle to show correctly in laravel livewire

I have a pivot table that links my products and categories together. What I'm trying to do is in my edit page for a product I
have a list of all the categories and each category has a toggle button that will enable or disable that category for that product.
The problem I'm having is that all my categories is set to enabled, but I only have one enabled and the rest is supposed to be disabled
I'm using laravel 8 and livewire
Here is my code
namespace App\Http\Livewire\Products;
use App\Models\Product;
use Livewire\Component;
use App\Models\Category;
class Edit extends Component
{
public Product $product;
public bool $enabled;
public $name;
public $description;
public function mount()
{
$pcPivot = $this->product->categories()->where('product_id', $this->product->id)->exists();
if($pcPivot === true)
{
$this->enabled = true;
}else{
$this->enabled = false;
}
$this->name = $this->product->name;
$this->description = $this->product->description;
}
public function render()
{
$categories = Category::all();
return view('livewire.products.edit', [
'categories' => $categories,
]);
}
}
and here is my edit.blade.php
<div>
<div class="md:grid md:grid-cols-3 md:gap-6">
<div class="md:col-span-1">
<div class="px-4 sm:px-0">
<h3 class="text-lg font-medium leading-6 text-gray-900">Edit Product</h3>
</div>
</div>
<div class="mt-5 md:mt-0 md:col-span-2">
<div class="shadow sm:rounded-md sm:overflow-hidden">
<form wire:submit.prevent="submit">
<div class="px-4 py-5 bg-white sm:p-6">
<div class="grid grid-cols-3 gap-6">
<div class="col-span-3 sm:col-span-2">
<label for="title" class="block text-sm font-medium leading-5 text-gray-700">
Name
</label>
<div class="rounded-md shadow-sm">
<input id="name" wire:model="product.name" class="flex-1 form-input block w-full min-w-0 transition duration-150 ease-in-out sm:text-sm sm:leading-5">
</div>
</div>
</div>
</div>
<div class="px-4 py-5 bg-white sm:p-6">
<div class="grid grid-cols-3 gap-6">
<div class="col-span-3 sm:col-span-2">
<label for="description" class="block text-sm font-medium leading-5 text-gray-700">
Description
</label>
<div class="rounded-md shadow-sm">
<textarea id="description" wire:model="product.description" rows="3" class="form-textarea mt-1 block w-full transition duration-150 ease-in-out sm:text-sm sm:leading-5"></textarea>
</div>
</div>
</div>
</div>
<div class="px-4 py-3 bg-gray-50 text-right sm:px-6">
<span class="inline-flex rounded-md shadow-sm">
<button type="submit" class="inline-flex justify-center py-2 px-4 border border-transparent text-sm leading-5 font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-500 focus:outline-none focus:border-indigo-700 focus:shadow-outline-indigo active:bg-indigo-700 transition duration-150 ease-in-out">
Update
</button>
</span>
</div>
</form>
</div>
</div>
</div>
#include('spacer')
<div class="md:grid md:grid-cols-3 md:gap-6">
<div class="md:col-span-1">
<div class="px-4 sm:px-0">
<h3 class="text-lg font-medium leading-6 text-gray-900">Categories</h3>
</div>
</div>
<div class="mt-5 md:mt-0 md:col-span-2">
<div class="shadow sm:rounded-md sm:overflow-hidden">
<table class="min-w-full divide-y divide-gray-200">
<thead>
<tr>
<x-th>Title</x-th>
<x-th>Enable/Disable</x-th>
</tr>
</thead>
<tbody class="bg-white divide-y divide-gray-200">
#foreach($categories as $category)
<tr>
<td class="px-6 py-4 whitespace-no-wrap">
<div class="flex items-center">
<div class="text-sm font-medium text-gray-900">
{{ $category->title }}
</div>
</div>
</td>
<td class="px-6 py-4 whitespace-no-wrap">
<div class="mt-1 flex rounded-md">
<span role="checkbox" tabindex="0" aria-checked="false" class="#if($enabled) bg-indigo-600 #else bg-gray-200 #endif relative inline-flex flex-shrink-0 h-6 w-11 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 focus:outline-none focus:shadow-outline">
<span aria-hidden="true" class="#if($enabled) translate-x-5 #else translate-x-0 #endif inline-block h-5 w-5 rounded-full bg-white shadow transform transition ease-in-out duration-200">
<input id="enabled" type="checkbox" wire:model="enabled" class="invisible">
</span>
</span>
</div>
</td>
</tr>
#endforeach
</tbody>
</table>
</div>
</div>
</div>
</div>
If you check the documentation for Livewire, at lifecycle hooks... you will see that:
mount : Runs once, immediately after the component is instantiated, but before render() is called
So basically you are getting an "enabled" value once, before rendering the component,then you start rendering it, with that foreach, using the same "enabled" from mount for each item of your dataset.
Consider building your cursor with the enabled value inside for each record.

Resources