F
Filament11mo ago
ehbfa

Open up a modal from a dashboard widget

Heya! I've got a widget which displays some text and at the end a button. When the user clicks that button, I want to open a modal window. Now I think stuff like this is possible, when I look at this: https://filamentphp.com/docs/3.x/support/blade-components/modal#controlling-a-modal-from-javascript - but my two questions are; 1) Where to place that modal HTML, that it can be accessed via JS? How/where do I register it, so it becomes available in the DOM, for JS to access it? Or am I missing something about how this all works. 2) Can I just load in other HTML in that modal as well? As the modal will have additional buttons that needs to be pressed to progress the flow within that modal. I'm sorry for these newbee questions, but I'm mostly a backend dev, and not too familiar with Livewire or Alpine... So some pointers on where to place the content provided in that example and get me started is much appreciated!
36 Replies
toeknee
toeknee11mo ago
You should just be able to call an Action and use ->view() to call the vlade view /If you want buttons and flow within the modal, then that's a form and you would use a form on the action
ehbfa
ehbfa11mo ago
Sorry, can you please dumb this down for me? Call an action from where, from within that widget? And use the ->view() on that action..? And that view then has to be the modal html? Or the content that needs to be in that modal?
toeknee
toeknee11mo ago
An action is a link/button that triggers a modal. You call it from wherever you want the action to be triggered from. Did you read the above docs?
ehbfa
ehbfa10mo ago
I did read those docs. But I think we are talking about two different things? This is the code of my widget:
<?php

namespace App\Filament\Widgets;

use App\Traits\WidgetsTrait;
use Filament\Widgets\Widget;

class PlusThemes extends Widget
{

protected static string $view = 'filament.widgets.plus-themes';

protected function getViewData(): array
{
$tenant = resolve('tenant');
$tenant->loadMissing('textSuggestionThemes');

return [
'firstTheme' => $tenant->textSuggestionThemes->first(),
];
}

}
<?php

namespace App\Filament\Widgets;

use App\Traits\WidgetsTrait;
use Filament\Widgets\Widget;

class PlusThemes extends Widget
{

protected static string $view = 'filament.widgets.plus-themes';

protected function getViewData(): array
{
$tenant = resolve('tenant');
$tenant->loadMissing('textSuggestionThemes');

return [
'firstTheme' => $tenant->textSuggestionThemes->first(),
];
}

}
And this is the contents of the view;
<div class="plus-themes-widget col-[--col-span-default] text-kto-black" style="--col-span-default: span 2 / span 2;">
<x-filament-widgets::widget>
<x-filament::card>
{{-- Widget content --}}

<h2 class="text-xl font-semibold tracking-tight filament-card-heading">Hi {{ auth()->user()->name }}!</h2>


<p id="typed-text" class="text-sm font-medium">Some text</p>

<button x-on:click="$dispatch('open-modal', { id: 'custom-modal-handle' })">
Open modal
</button>

</x-filament::card>
</x-filament-widgets::widget>
</div>
<div class="plus-themes-widget col-[--col-span-default] text-kto-black" style="--col-span-default: span 2 / span 2;">
<x-filament-widgets::widget>
<x-filament::card>
{{-- Widget content --}}

<h2 class="text-xl font-semibold tracking-tight filament-card-heading">Hi {{ auth()->user()->name }}!</h2>


<p id="typed-text" class="text-sm font-medium">Some text</p>

<button x-on:click="$dispatch('open-modal', { id: 'custom-modal-handle' })">
Open modal
</button>

</x-filament::card>
</x-filament-widgets::widget>
</div>
Now I am probably missing something, but where to place an action in this logic? I want that <button> to somehow open a modal, or however that works 🙂 I tried to do something with that $dispatch, but couldn't figure out how to do that or get that to work 😦
chrislcarr
chrislcarr10mo ago
Hi @wyChoong and @toeknee, I am the colleague of @ehbfa who is trying to get this working. I have literally been at this for several days and can not get anything working. I'm exhausted from wasting my time with ChatGPT too. I went down the path of setting up a Livewire component for the modal since the documentation links you provided are much too vague for a frontend developer such as myself. I am now currently tangled up in the weeds of Livewire & Alpine. Nothing is working and/or Livewire isn't recognized in the proper place, yada yada yada. Obviously I am super frustrated. Here is what I want to do: * After creating a Livewire component, I have a resources/views/livewire/themes-modal.blade.php file which contains a mix of html and javascript for displaying/generating content. * I want that to render in a modal when I click on a button in my resources/views/filament/widgets/themes.blade.php file, which is being displayed on our Dashboard Filament "page". Is this even possible? I think my "normal" approaches are conflicting with some deep-rooted Filament code?
toeknee
toeknee10mo ago
Just use a filamentphp Action with a ViewAction that loads in a ->view() Where are you tyring to call it
wyChoong
wyChoong10mo ago
you are wasting your time as you are using chatgpt show your code in gist what have you tried
toeknee
toeknee10mo ago
I missed that, yeah don't even think about using ChatGPT for Livewire or Filament
chrislcarr
chrislcarr10mo ago
I know about ChatGPT, that’s why I said I was wasting my time. I’m exhausted now and it’s 19:10 so I’ll get back at it tomorrow.
chrislcarr
chrislcarr10mo ago
https://gist.github.com/ChrisLCarrBF/77f718f07e5cd91650c1522b256925cc I know this is a bit f'ed up because of stupid ChatGPT. ¯\_(ツ)_/¯ I'm just trying to get the contents of resources/views/livewire/themes-modal.blade.php to display in a modal when the "Open Themes Suggestions modal" button is clicked in resources/views/filament/widgets/katoo-plus-themes.blade.php. I didn't think it would be so hard ... so I'm feeling pretty stupid and nobody likes to feel that way. As a reminder, I am a frontend developer with limited experience working with backend PHP code, so please keep that in mind.
Gist
ThemesModal.php
GitHub Gist: instantly share code, notes, and snippets.
toeknee
toeknee10mo ago
So this is in the frontend outside of filament admin correct? This is how you run a simple Toggle as a frontend dev, without using the backend at all in Livewire/Alpine:
<div>
<!-- Modal -->
<div x-data="{ open: false }">
<button @click="open = ! open">Toggle Modal</button>
<div x-show="open" class="modal class">
Modal contents...
</div>
</div>
</div>
<div>
<!-- Modal -->
<div x-data="{ open: false }">
<button @click="open = ! open">Toggle Modal</button>
<div x-show="open" class="modal class">
Modal contents...
</div>
</div>
</div>
Then you can structure the modal classes to render a modal however you want. If you are rendering assets in the frontend using filament then we need more code / understanding.
chrislcarr
chrislcarr10mo ago
No, it is inside of Filament admin. I have a widget that is rendered on the Dashboard. Within that widget, I have a button that should open a modal when its clicked on.
toeknee
toeknee10mo ago
Right you have massively over complicated it
chrislcarr
chrislcarr10mo ago
Hahahaha
toeknee
toeknee10mo ago
Where in the filament admin are you trying to render the button
chrislcarr
chrislcarr10mo ago
In my gist, I have a widget resources/views/filament/widgets/katoo-plus-themes.blade.php that is being displayed on the Dashboard. There is a button in that widget file that should open a modal when it is clicked on. That modal should contain the contents of my Livewire component's view resources/views/livewire/themes-modal.blade.php.
toeknee
toeknee10mo ago
Right but none of that is the filamenet admin they are frontend resources, so you must have a widget class file that calls them? Like: /app/Filament/widgets/KatooPlusThemes.php
chrislcarr
chrislcarr10mo ago
Duh. Right, of course! Sorry about that. I just added app/Filament/Widgets/KatooPlusThemes.php to my gist.
toeknee
toeknee10mo ago
Ok I see, it's actually much easier than you think. Give me a minute
toeknee
toeknee10mo ago
See how it allows you to include the filament modals and you call the php action which can then render a view Then the themeAction(): action could be like:
public function themeAction(): Action
{
return Action::make('theme')
->form([
ViewField::make('katooplustheme')
->view('livewire.themes-modal')
])
->modalWidth('2xl')
->action(fn () => '');
}
public function themeAction(): Action
{
return Action::make('theme')
->form([
ViewField::make('katooplustheme')
->view('livewire.themes-modal')
])
->modalWidth('2xl')
->action(fn () => '');
}
This means the themeAction will render the livewire.themes-modal content
chrislcarr
chrislcarr10mo ago
Yes, I had been trying to follow that but I could only get a button to show up in the Livewire component's view resources/views/livewire/themes-modal.blade.php. I need it in the widget. I was getting lost in translating the example's backend class specifics of a delete modal.
toeknee
toeknee10mo ago
Then you must have missed {{ $this->themeAction }} <x-filament-actions::modals /> from the file as the button shows up as soomn as you include the action
chrislcarr
chrislcarr10mo ago
No, I didn't miss that. I just don't have the knowledge/experience of putting that in a different class since the example was using it in the Livewire component's view.
toeknee
toeknee10mo ago
So it's super simple Here I created a ButtonWidget heres the code
<?php

namespace App\Filament\Widgets\Dashboard;

use Filament\Actions\Action;
use Filament\Actions\Concerns\InteractsWithActions;
use Filament\Actions\Contracts\HasActions;
use Filament\Forms\Components\ViewField;
use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Contracts\HasForms;
use Filament\Widgets\Widget;

class ButtonWidget extends Widget implements HasForms, HasActions
{

use InteractsWithActions;
use InteractsWithForms;

protected static string $view = 'filament.widgets.dashboard.button-widget';

public function themeAction(): Action
{
return Action::make('theme')
->form([
ViewField::make('katooplustheme')
->view('my-blade-view')
])
->modalWidth('2xl')
->action(fn () => '');
}
}
<?php

namespace App\Filament\Widgets\Dashboard;

use Filament\Actions\Action;
use Filament\Actions\Concerns\InteractsWithActions;
use Filament\Actions\Contracts\HasActions;
use Filament\Forms\Components\ViewField;
use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Contracts\HasForms;
use Filament\Widgets\Widget;

class ButtonWidget extends Widget implements HasForms, HasActions
{

use InteractsWithActions;
use InteractsWithForms;

protected static string $view = 'filament.widgets.dashboard.button-widget';

public function themeAction(): Action
{
return Action::make('theme')
->form([
ViewField::make('katooplustheme')
->view('my-blade-view')
])
->modalWidth('2xl')
->action(fn () => '');
}
}
This is the widget, The themeAction() is auto rendered with $this->themeAction in the view This is my Blade View for the Action
<x-filament-widgets::widget>
<x-filament::section>
{{-- Widget content --}}
{{ $this->themeAction }}

<x-filament-actions::modals />
</x-filament::section>
</x-filament-widgets::widget>
<x-filament-widgets::widget>
<x-filament::section>
{{-- Widget content --}}
{{ $this->themeAction }}

<x-filament-actions::modals />
</x-filament::section>
</x-filament-widgets::widget>
This will render everything placed within the into the before
Action::make('theme')
->form([
ViewField::make('katooplustheme')
->view('my-blade-view')
])
->modalWidth('2xl')
->action(fn () => '');
Action::make('theme')
->form([
ViewField::make('katooplustheme')
->view('my-blade-view')
])
->modalWidth('2xl')
->action(fn () => '');
Then the ->view('') here loads the blade view: my-blade-view From resources etc as normal.
chrislcarr
chrislcarr10mo ago
Wow, this is super helpful. Thanks!
toeknee
toeknee10mo ago
You are very welcome, then you can look into the options for the Action too. Since ->action(fn () => '') for example accepts php code to actually process stuff. It's crazy powerful and why Dan made it available through the entire Livewire ecosystem All sorted now?
chrislcarr
chrislcarr10mo ago
Partially. I do indeed have a modal showing up now. However, of course, the code in resources/views/themes-modal.blade.php is no longer being generated because of DOMContentLoaded. Now that this is being brought in through a modal instead of a page, what should I use instead? Do I need to pass stuff in with ->action(fn () => '')? I've updated my gist with the current code that I'm using: https://gist.github.com/ChrisLCarrBF/77f718f07e5cd91650c1522b256925cc I do have another question ... * we've used the "Actions - Modals" approach (https://filamentphp.com/docs/3.x/actions/modals), * but since I'm not working with forms or anything but am rather just displaying content generated by javascript, * would it have been better to go with the "Core Concepts - Blade Components - Modal Blade component" approach (https://filamentphp.com/docs/3.x/support/blade-components/modal) instead??? * what are the differences?
chrislcarr
chrislcarr10mo ago
Also, another very strange thing - when I click the "Lees mijn verbeteringen" Action button to trigger the modal, the content in "#typed-text" and "#katoo-plus-continue" is being completely wiped out and only leaving the "Lees mijn verbeteringen" Action button. Any idea why that's happening when the modal is opened?
chrislcarr
chrislcarr10mo ago
Please note that this is not happening when I use the <x-filament::modal> . . . </x-filament::modal> approach as described in https://filamentphp.com/docs/3.x/support/blade-components/modal. 🤔
toeknee
toeknee10mo ago
Yes doing modals like that would work, but my understanding is you want the modal to have interaction with the server hence an Action made more sense
chrislcarr
chrislcarr10mo ago
Ah OK, gotcha.