I’m trying to create a data table where user can click on “Add Row” button to create new row inside the <tbody>
To give context, the table will contains the data of developers and their skill. the developers are categorized into Frontend and Backend, which each category is a Livewire component of <tbody>
.
Each row in the <tbody>
Livewire component will have 2 child Livewire which contain two <input type=text>
Here is the screenshot of the table with initial data:
The goal is to be able to add new row (developer) on their category (frontend or backend), the text input component will do validation. in the event both input fields are valid, the table body (<tbody>
) component will create a new record in the database.
The problem i’m getting is that when the Add Row button clicked more than once, I’ll get this error: Uncaught (in promise) TypeError: initialData is null
On other thread in this forum, someone have similar error and could be solved by wrapping the component in a <div>
and/or assigning unique key()
value. I did both however it didn’t solve the issue i encounter.
So below is my code:
TableController.php:
final class TableController
{
public function show()
{
$columns = ['name', 'skill'];
$tableData = [
[
['John', 'ReactJS'],
['Laura', 'VueJS'],
],
[
['Max', 'PHP'],
['Max', 'Node'],
],
];
return view('data-table.page', [
'columns' => $columns,
'tableData' => $tableData,
]);
}
}
data-table.page.blade.php:
@extends('layouts.app')
@section('content')
@include('data-table.table', ['columns' => $columns, 'tableData' => $tableData])
@endsection
data-table.table.blade.php:
<table class="table table-sm">
<thead>
<tr>
@foreach($columns as $name)
<th>{{ $name }}</th>
@endforeach
</tr>
</thead>
@foreach($tableData as $data)
<livewire:data-table.table-body :data="$data" />
@endforeach
</table>
livewire/data-table.table-body.blade.php:
<tbody>
@foreach($data as $row)
<tr>
@foreach($row as $index => $cell)
<td><livewire:data-table.text-input :input="$cell" :key="'tr-' . $loop->index . '-' . $cell" /></td>
@endforeach
</tr>
@endforeach
<tr>
<td colspan="2"><button wire:click="addRow">Add Row</button></td>
</tr>
</tbody>
TableBody.php:
class TableBody extends Component
{
public $data;
public function addRow()
{
$this->data[] = ['', ''];
}
public function render()
{
return view('livewire.data-table.table-body');
}
}
livewire/data-table.text-input.blade.php
<div>
<input wire:model.debounce.500ms="input" type="text">
<span>{{ $input }}</span>
</div>
TextInput.php:
class TextInput extends Component
{
public $input;
public function render()
{
return view('livewire.data-table.text-input');
}
}