Closed Namoshek closed 3 years ago
Thanks for sharing, I haven't tried livewire yet and surely will use this as a ref when I got the chance to play with it.
Hello @Namoshek I am a bit new with LiveWire. I am trying to render a Livewire component on a custom 'actions' column but without success. I would like to have a livewire button component loaded in a custom datatable 'actions' column.
$query = $this->userRepository->getIndexQuery();
return DataTables::of($query)
->addColumn('roles', function (User $user) {
return $user->roles->implode('name', ', ');
})
->addColumn('actions', function (User $user) {
// render livewire component (button)
})
->rawColumns(['actions'])
->make(true);
Do you have any hints maybe? thank you a lot
You just need to return the html which renders the livewire component from the closure, similar to what you would use in a view.
Thanks for your reply! I tried this way but cannot make it work:
Notes:
the JS callback works (tried triggering a JS alert), no errors in the browser console
I have the JS callback set up in the datatable:
tableElement.DataTable({
"serverSide" : true,
"order" : {!! $order ?? "[]" !!},
"lengthMenu" : [[10, 50, 100, 200, -1], [10, 50, 100, 200, "Tutti"]],
"searching" : true,
"deferRender" : true,
"ordering" : true,
"paging" : true,
"orderCellsTop": true,
drawCallback : function(settings) {
if (window.livewire) {
window.livewire.rescan();
}
},
On the Laravel Controller I tried these two ways:
return the view:
$query = $this->userRepository->getIndexQuery();
return DataTables::of($query)
->addColumn('roles', function (User $user) {
return $user->roles->implode('name', ', ');
})
->addColumn('actions', function (User $user) {
return view('livewire.block-user-button');
})
->rawColumns(['actions'])
->toJson();
Return directly the HTML:
$query = $this->userRepository->getIndexQuery();
return DataTables::of($query)
->addColumn('roles', function (User $user) {
return $user->roles->implode('name', ', ');
})
->addColumn('actions', function (User $user) {
return <<<'HTML'
<div>
<input wire:model="buttonText" wire:click="myAction" type="text">
</div>
HTML;
})
->rawColumns(['actions'])
->toJson();
But unfortunately clicking the button does not trigger the component PHP function.
Do you have any other possible hint maybe? Would be super nice to use livewire to handle these button functionality
Your HTML is not a Livewire component, it's the template of the component. You need to return the call to the component, for example <livewire:counter>
when we stick with the example component from the quickstart guide.
Thank you for your suggestion @Namoshek!.
I have been able to make the Livewire component work in a Datatable column this way:
$query = $this->userRepository->getIndexQuery();
return DataTables::of($query)
->addColumn('roles', function (User $user) {
return $user->roles->implode('name', ', ');
})
->addColumn('actions', function (User $user) {
return Livewire::mount('block-user-button', ['user' => $user])->html();
})
->rawColumns(['actions'])
->toJson();
I was able to work with livewire now and the code suggestions here works great. I also added a new api on html builder to integrate with livewire as per suggestion of @Namoshek 🎊
public function html()
{
return $this->builder()
->setTableId('videos-table')
->columns($this->getColumns())
->minifiedAjax()
->drawCallbackWithLivewire() // enable livewire integration
...
Tried implementing this with wire:poll
for automatic loading of status from a job queue. Great work around for a realtime checking of row status with dataTables. ^_^
Cool stuff, thank you!
super nice! Thank you @yajra :D
Hello, guys. It's still a blur on my side. Can anybody suggest how this issue is dealt with if we are doing livewire inside custom colums? Something similar to this code:
const dt = table.DataTable( {
columns: [
{ data: 'id', render: (data, type, row, meta) => {
return `<a href="#" as="button" wire:click.prevent="edit(${data})">Edit</a>`;
}},
],
...
});
With that code, function edit()
is not being called. Thanks!
@jhourlad If you use custom JavaScript render functions, the Blade component tags like <livewire:counter />
are not parsed and rendered correctly.
See my earlier comment as how to render Livewire components. You need to use a raw column which renders the Livewire component tag. And you need to add the new builder helper method yajra showed here.
This is how i add my button but it is still don't work
![Uploading dataTables_button.PNG…]()
front datatable any suggestion on how that is the proper way of displaying the datables? by the way i'm a newbie in laravel i just only starting to study it this day i badly need your help
Hello, guys. It's still a blur on my side. Can anybody suggest how this issue is dealt with if we are doing livewire inside custom colums? Something similar to this code:
const dt = table.DataTable( { columns: [ { data: 'id', render: (data, type, row, meta) => { return `<a href="#" as="button" wire:click.prevent="edit(${data})">Edit</a>`; }}, ], ... });
With that code, function
edit()
is not being called. Thanks!
I have been stuck with your same problem. Does anyone have a working example? I can't figure it out with the guidelines given.
thank you
was anyone able to make the livewire click work?
was anyone able to make the livewire click work?
You mean a clickable button for example, like <button wire:click="foo">
? Absolutely, it requires no special handling.
was anyone able to make the livewire click work?
You mean a clickable button for example, like
<button wire:click="foo">
? Absolutely, it requires no special handling.
It doesn't work with me though, there's no requests happening in Network tab when clicking and not performing the click
View:
<div>
<button wire:click="increment">+</button>
<h1>{{ $count }}</h1>
</div>
Component:
class Actions extends Component
{
public $count = 0;
public function increment()
{
$this->count++;
}
public function render()
{
return view('livewire.permission.actions');
}
}
datatable
public function dataTable($query)
{
return datatables()
->eloquent($query)
->editColumn('created_at', function ($data) {
return $data->created_at->format('Y/m/d');
})
->editColumn('action', function ($data) {
return Livewire::mount('permission.actions', ['permission' => $data->id])->html();
})
->rawColumns(['action']);
}
and scripts are like this on layout
@livewireScripts
<script src="{{ mix('js/app.js') }}"></script>
@stack('scripts')
</body>
</html>
How does the relevant part of your DataTable look like? Have you added the draw callback, which Yajra added to the package?
How does the relevant part of your DataTable look like? Have you added the draw callback, which Yajra added to the package?
yes, I did add it
public function dataTable($query)
{
return datatables()
->eloquent($query)
->editColumn('created_at', function ($data) {
return $data->created_at->format('Y/m/d');
})
->editColumn('action', function ($data) {
return Livewire::mount('permission.actions', ['permission' => $data->id])->html();
})
->rawColumns(['action']);
}
public function html()
{
return $this->builder()
->setTableId('permissions-table')
->columns($this->getColumns())
->drawCallbackWithLivewire()
->addAction(['width' => '80px'])
->orderBy(1);
}
My code looks a bit different, but I swapped it for your style (didn't know the Livewire::mount()->html()
yet) and it works as well.
Are you rendering the scripts for your DataTable? Or is this some manually written stuff?
<div>
{{ $dataTable->table([], true) }}
</div>
@push('scripts')
{!! $dataTable->scripts() !!}
@endpush
My code looks a bit different, but I swapped it for your style (didn't know the
Livewire::mount()->html()
yet) and it works as well.Are you rendering the scripts for your DataTable? Or is this some manually written stuff?
<div> {{ $dataTable->table([], true) }} </div> @push('scripts') {!! $dataTable->scripts() !!} @endpush
this is weird, this is how the view
<x-app-layout>
<div class="row">
<div class="col-12">
<div class="card">
<div class="card-body">
<div class="row mb-2">
<div class="col-sm-4">
@livewire('permission.create')
</div>
</div>
<div class="table-responsive">
<div class="table-responsive">
{{ $dataTable->table(['class' =>'table table-centered table-striped dt-responsive nowrap w-100'], true) }}
</div>
</div>
</div>
</div>
</div>
</div>
@push('scripts')
{!! $dataTable->scripts() !!}
@endpush
</x-app-layout>
what's your livewire version might be some bug in the newer versions..
Latest, this is weird. I guess the browser is also not showing any click event handlers for the button?
Latest, this is weird. I guess the browser is also not showing any click event handlers for the button?
no requests happens when I click the button, also the component doesn't show up on the chrome livewire extension.
the HTML only is being injected to the view. Do I have to pass scripts in drawCallbackWithLivewire()
?
how did u type ur code before knowing about Livewire::mount()->html()
I'm using ->editColumn('action', 'some.view.name')
in my DataTable and <livewire:my.component :foo="$model" :bar="true" />
in the view for example. But as said, I tried your style and it works the same (and is definitely nicer 👍).
I was able to work with livewire now and the code suggestions here works great. I also added a new api on html builder to integrate with livewire as per suggestion of @Namoshek 🎊
public function html() { return $this->builder() ->setTableId('videos-table') ->columns($this->getColumns()) ->minifiedAjax() ->drawCallbackWithLivewire() // enable livewire integration ...
Tried implementing this with
wire:poll
for automatic loading of status from a job queue. Great work around for a realtime checking of row status with dataTables. ^_^
Hello, where you create this html()
method? is it inside the component?
@mahendra2448 You'll need yajra/laravel-datatables-html
for this. The usage is described in the documentation.
Note: This is not a bug report or an issue. Prior to trying it out myself, I searched for the keyword
livewire
in the issues and did not find what I was looking for. So I thought, I leave a hint for future readers with a similar question. This issue may be closed at any time.I always wanted to have dynamic components within my tables, but unfortunately with vuejs, the default option provided by Laravel, this isn't possible. The vuejs core parses the DOM once when loading the page and switches then to a virtual DOM which is unaware of changes in the actual DOM. Therefore, when returning vuejs components from a DataTable, they are not recognized by vuejs and are simply not activated. And the alternative, plain JavaScript, was never an option for me either.
When learning about
livewire/livewire
, I thought it might be a suitable alternative for exactly this scenario. And it turns out, it is! (As long as you add a tiny but necessary configuration to your tables.)The only thing's I had to add to my DataTables configuration are the following two options:
The
deferLoading
option was necessary for me because I'm also using a self-written logic to save and restore the state of my tables, especially the column search state. Without the option, my tables performed three draw cycles when loading a page, which seemed to break the livewire logic (it happened quite fast, maybe that's why). If you are not using custom logic in theinitComplete
callback, you most likely don't need this option.The
drawCallback
is the actual sweetness needed to get things working. And it is straight forward as well. Whenever we finish drawing the table (which happens when loading new data, e.g. on search, sort or page change), we ask livewire to look for new components and initialize them. That's it. livewire will even make sure to subscribe to new Laravel Echo channels, if any of the newly recognized components listens for some events. Unfortunately though, it won't unsubscribe when components (i.e. table data) are replaced with new ones. For me, this isn't an issue though.