z-song / laravel-admin

Build a full-featured administrative interface in ten minutes
https://laravel-admin.org
MIT License
11.13k stars 2.81k forks source link

Model popup using AJAX to show current contents and icon change #5701

Open technilogics opened 1 year ago

technilogics commented 1 year ago

Description:

I am using Grid Column Model to load Related Notes, but unfortunately it has 2 issues

  1. Icon for Column is always Clone icon, there is no way to change it Screenshot 2022-12-20 at 19-42-27 Admin Orders
  2. All popup data is loaded with page load, how to load it using AJAX on Icon click, so latest records can be shown.

Steps To Reproduce:

`$grid->column('notes', __('Notes'))->display(function ($title, $column) { $notes = $this->notes()->with('admin:id,name')->take(10)->orderBy('id','desc')->get()->map(function ($note) { //return $note->only(['id','description','admin_user_id' , 'created_at']); return [$note->id,nl2br($note->description ."\n\r\n\rBy ".$note->admin->name ." @ ".date("d/m/Y h:i A",strtotime($note->created_at)))]; }); // dd($notes->flatten()->toArray()); // Otherwise it is displayed as editable if(count($notes)>0){ //Show Icon, and show Notes in model popup if count greater than 0 return $column->modal('Latest Notes', function ($column) use($notes) { return new Table(['ID', 'Description'], $notes->toArray(),['table-striped']); //return new Box('No Information', 'There is no note to show'); });

}else{
  return "-";//Donot show Icon
}

});`

alexoleynik0 commented 1 year ago

Was curious about this too and here's what I've found. $grid->column('files')->model($title, $callback = null); accepts two arguments, and the $callback one can be an actual \Closure that returns a string/Renderable (as in the docs' example), or a name of the class that implements \Illuminate\Contracts\Support\Renderable.

In the last case, no render will be called during the Grid render, but ajax load using admin.handle-renderable will be made on the icon click.

It will pass to your Renderable the "key" (primaryKey / id) of the current row, and everything else is just similar to what you do in the callback with tiny adjustments.

For example:

class PostFilesRenderable implements \Illuminate\Contracts\Support\Renderable {
    public function render() {
        $files = File::query()->select(['id', 'path'])->where('post_id', request('key'))->get()->map(function($item) {
            $item->size = file_size(\Illuminate\Support\Facades\Storage::disk('admin')->size($item->path));
            return $item;
        });
        $table = new \Encore\Admin\Widgets\Table(['ID', 'Path', 'Size'], $files->toArray());
        return $table->render() . "<h4>Total files: " . $files->count() . "</h4>";
    }
}

Your controller's grid:

$grid->column('files')->model('Files', PostFilesRenderable);
alexoleynik0 commented 1 year ago

As to "fa-clone" icon change - it's hardcoded into resources/views/components/column-modal.blade.php. But you can override this view if you really need it, as described here.

In your app/Admin/bootstrap.php:

app('view')->prependNamespace('admin', resource_path('views/vendor/laravel-admin'));

You need to follow the same dir structure, so for admin::components.column-modal (from Encore\Admin\Grid\Displayers\Modal@display) you need to create file in views/vendor/laravel-admin/components.column-modal with the same content as in original + your modifications. Example of the first 3 lines edited:

@if ($value == 0)
    <span data-toggle="modal" data-target="#grid-modal-{{ $name }}" data-key="{{ $key }}">
        <a href="javascript:void(0)"><i class="fa fa-eye"></i>&nbsp;&nbsp;{{ $value }}</a>
    </span>
@else
    <span> --- </span>
@endif

OR you can just simply don't display anything for the column if you don't want to, depending on the original value:

$grid->column('files')->model('Files', PostFilesRenderable)
    ->display(function (string $c, Grid\Column $column) {
        return $column->getOriginal() ? $c : '---';
    });
technilogics commented 1 year ago

Hi @alexoleynik0 thanks for these directions, it help me in achieving goal. I was busy, when you suggest. Today i spare time to implement it.

but there are a couple of things that i face, so i wants to share, it may help others.

1. $grid->column('files')->model('Files', PostFilesRenderable);
 here model should be modal

2. modal accept class i.e. instead of PostFilesRenderable we have to write PostFilesRenderable:class

regarding icon instead of copying view i use the struct you provided to control display

$grid->column('files')->model('Files', PostFilesRenderable)
    ->display(function (string $c, Grid\Column $column) {
        return $column->getOriginal() ? $c : '---';
    });

in my case for notes i also count notes available as notes_count, as follow

$grid->column('notes_count',  __('Notes'))->modal(__('Notes'),ShowNote::class)
  ->display(function (string $c, Grid\Column $column) {
  if($column->getOriginal()==0){ //if notes_count is 0
    return '-';
  }
        return str_replace('fa-clone','fa-eye',$c); //replace icon with your icon of choice
    });

Thank you for your help.