I follow the screencasts serie Building a Datatable.
But I have a problem with the edit form.
When I click the Edit button, the modal form appears, but the date which can be updated is not shown in the date field.
I use the Pikaday date picker.
I do everything the same as explained in the video. I do not understand.
App\Models
<?php
namespace App\Models;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;
class Transaction extends Model
{
use HasFactory;
const STATUSES = [
'success' => 'Success',
'failed' => 'Failed',
'processing' => 'Processing',
];
protected $guarded = [];
protected $casts = ['date' => 'date'];
public function getStatusColorAttribute()
{
return [
'success' => 'green',
'failed' => 'red',
][$this->status] ?? 'cool-gray';
}
public function getDateForHumansAttribute()
{
return $this->date->format('M, d Y');
}
public function getDateForEditingAttribute()
{
return $this->date->format('m/d/Y');
}
public function setDateForEditingAttribute($value)
{
$this->date = Carbon::parse($value);
}
}
The Date Component
<div
x-data="{ value: @entangle($attributes->wire('model')), picker: undefined }"
x-init="new Pikaday({ field: $refs.input, format: 'MM/DD/YYYY', onOpen() { this.setDate($refs.input.value) } })"
type="text"
x-on:change="value = $event.target.value"
class="flex rounded-md shadow-sm"
>
<span class="inline-flex items-center px-3 rounded-l-md border border-r-0 border-gray-300 bg-gray-50 text-gray-500 sm:text-sm">
<svg class="h-5 w-5 text-gray-400" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" clip-rule="evenodd" d="M6 2C5.44772 2 5 2.44772 5 3V4H4C2.89543 4 2 4.89543 2 6V16C2 17.1046 2.89543 18 4 18H16C17.1046 18 18 17.1046 18 16V6C18 4.89543 17.1046 4 16 4H15V3C15 2.44772 14.5523 2 14 2C13.4477 2 13 2.44772 13 3V4H7V3C7 2.44772 6.55228 2 6 2ZM6 7C5.44772 7 5 7.44772 5 8C5 8.55228 5.44772 9 6 9H14C14.5523 9 15 8.55228 15 8C15 7.44772 14.5523 7 14 7H6Z"/>
</svg>
</span>
<input
{{ $attributes->whereDoesntStartWith('wire:model') }}
x-ref="input"
x-bind:value="value"
class="rounded-none rounded-r-md flex-1 form-input block w-full transition duration-150 ease-in-out sm:text-sm sm:leading-5"
/>
</div>
@push('styles')
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/pikaday/css/pikaday.css">
@endpush
@push('scripts')
<script src="https://unpkg.com/moment"></script>
<script src="https://cdn.jsdelivr.net/npm/pikaday/pikaday.js"></script>
@endpush
Here the Dashboard.php component
<?php
namespace App\Http\Livewire;
use App\Models\Transaction;
use Livewire\Component;
use Livewire\WithPagination;
class Dashboard extends Component
{
use WithPagination;
public $search = '';
public $sortField = 'id';
public $sortDirection = 'asc';
public $showEditModal = false;
public Transaction $editing;
protected $queryString = ['sortField', 'sortDirection'];
public function rules()
{
return [
'editing.title' => 'required|min:3',
'editing.amount' => 'required',
'editing.status' => 'required|in:'.collect(Transaction::STATUSES)->keys()->implode(','),
'editing.date_for_editing' => 'required',
];
}
public function mount()
{
$this->editing = $this->makeBlankTransaction();
// $this->editing = Transaction::make(['date' => now()]);
// dd($this->editing);
}
public function sortBy($field)
{
$this->sortDirection = $this->sortField === $field
? $this->sortDirection = $this->sortDirection === 'asc' ? 'desc' : 'asc'
: 'asc';
$this->sortField = $field;
}
public function makeBlankTransaction()
{
return Transaction::make(['date' => now(), 'status' => 'success']);
}
public function create()
{
if ($this->editing->getKey()) $this->editing = $this->makeBlankTransaction();
$this->showEditModal = true;
}
public function edit(Transaction $transaction)
{
if ($this->editing->isNot($transaction)) $this->editing = $transaction;
$this->showEditModal = true;
}
public function save()
{
$this->validate();
$this->editing->save();
$this->showEditModal = false;
}
public function render()
{
return view('livewire.dashboard', [
'transactions' => Transaction::search('title', $this->search)->orderBy($this->sortField, $this->sortDirection)->paginate(10),
]);
}
}
Here the dashboard.blade.php view with the modal form
<div>
<h1 class="text-2xl font-semibold text-gray-900">Dashboard</h1>
<div class="py-4 space-y-4">
<div class="flex justify-between">
<div class="w-1/4">
<x-input.text wire:model="search" placeholder="Search Transactions..." />
</div>
<div>
<x-button.primary wire:click="create"><x-icon.plus/> New</x-button.primary>
</div>
</div>
<div class="flex-col space-y-4">
<x-table>
<x-slot name="head">
<x-table.heading sortable wire:click="sortBy('title')" :direction="$sortField === 'title' ? $sortDirection : null" class="w-full">Title</x-table.heading>
<x-table.heading sortable wire:click="sortBy('amount')" :direction="$sortField === 'amount' ? $sortDirection : null">Amount</x-table.heading>
<x-table.heading sortable wire:click="sortBy('status')" :direction="$sortField === 'status' ? $sortDirection : null">Status</x-table.heading>
<x-table.heading sortable wire:click="sortBy('date')" :direction="$sortField === 'date' ? $sortDirection : null">Date</x-table.heading>
<x-table.heading />
</x-slot>
<x-slot name="body">
@forelse ($transactions as $transaction)
<x-table.row wire:loading.class.delay="opacity-50">
<x-table.cell>
<span href="#" class="inline-flex space-x-2 truncate text-sm leading-5">
<x-icon.cash class="text-cool-gray-400"/>
<p class="text-cool-gray-600 truncate">
{{ $transaction->title }}
</p>
</span>
</x-table.cell>
<x-table.cell>
<span class="text-cool-gray-900 font-medium">€ {{ $transaction->amount }} </span>
</x-table.cell>
<x-table.cell>
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium leading-4 bg-{{ $transaction->status_color }}-100 text-{{ $transaction->status_color }}-800 capitalize">
{{ $transaction->status }}
</span>
</x-table.cell>
<x-table.cell>
{{ $transaction->date_for_humans }}
</x-table.cell>
<x-table.cell>
<x-button.link wire:click="edit({{ $transaction->id }})">Edit</x-button.link>
</x-table.cell>
</x-table.row>
@empty
<x-table.row>
<x-table.cell colspan="4">
<div class="flex justify-center items-center space-x-2">
<x-icon.inbox class="h-8 w-8 text-cool-gray-400" />
<span class="font-medium py-8 text-cool-gray-400 text-xl">No transactions found...</span>
</div>
</x-table.cell>
</x-table.row>
@endforelse
</x-slot>
</x-table>
<div>
{{ $transactions->links() }}
</div>
</div>
</div>
<form wire:submit.prevent="save">
<x-modal.dialog wire:model.defer="showEditModal">
<x-slot name="title">Edit Transaction</x-slot>
<x-slot name="content">
<x-input.group for="title" label="Title" :error="$errors->first('editing.title')">
<x-input.text wire:model.lazy="editing.title" id="title" placeholder="Title" />
</x-input.group>
<x-input.group for="amount" label="Amount" :error="$errors->first('editing.amount')">
<x-input.money wire:model="editing.amount" id="amount" />
</x-input.group>
<x-input.group for="status" label="Status" :error="$errors->first('editing.status')">
<x-input.select wire:model.lazy="editing.status" id="status">
@foreach (App\Models\Transaction::STATUSES as $value => $label)
<option value="{{ $value }}">{{ $label }}</option>
@endforeach
</x-input.select>
</x-input.group>
<x-input.group for="date_for_editing" label="Date" :error="$errors->first('editing.date_for_editing')">
<x-input.date wire:model.lazy="editing.date_for_editing" id="date_for_editing" />
</x-input.group>
</x-slot>
<x-slot name="footer">
<x-button.secondary wire:click="$set('showEditModal', false)">Cancel</x-button.primary>
<x-button.primary type="submit">Save</x-button.primary>
</x-slot>
</x-modal.dialog>
</form>
</div>