F
Filamentβ€’12mo ago
Brian Kidd

Implement js library in custom widget

I have an app running on Inertia/Vue that I'm considering switching to Filament. My only hangup right now is that this app uses fullcalendar.io and specifically I need to render custom content for the event. I am aware of the fullcalendar plugin and have asked this question on that plugin's server but haven't gotten a response (https://discord.com/channels/883083792112300104/935819320699805737/1133498041144463411) What I am wondering is if there is any way in Filament/Livewire/Alpine to make use of the content injection functionality offered by fullcalendar (https://fullcalendar.io/docs/content-injection). Using the Vue fullcalendar library, this is trivial because I can simply return a Vue component to the eventContent function since, in the background, fullcalendar is using VDOM (preact). I realized I can create this HTML in a string in javascript and use the "arg" parameter that provides the calendar event for dynamic content but I am looking for a more elegant way to do this. Trying to do this in Filament may not be a good fit but want to get some advice before writing off Filament for this project. Thanks
Solution:
Okay so I have something like this: Widget.php ```php use Filament\Widgets\Widget;...
Jump to solution
6 Replies
JibayMcs
JibayMcsβ€’12mo ago
Hey ! πŸ‘‹ I've already build a custom Page using Fullcalendar. With the help of Livewire, you can easily make what you ask for πŸ™‚ The implementation is trivial too, since you can load external Scripts or CSS using something like this:
// You can use external link to your scripts or css
FilamentAsset::register([
Js::make('fullcalendar-js', 'https://fullcalendar-script.js')->loadedOnRequest(),
Css::make('fullcalendar-css', 'https://fullcalendar-css.css'),
]);
// You can use external link to your scripts or css
FilamentAsset::register([
Js::make('fullcalendar-js', 'https://fullcalendar-script.js')->loadedOnRequest(),
Css::make('fullcalendar-css', 'https://fullcalendar-css.css'),
]);
More documentation: https://filamentphp.com/docs/3.x/support/assets#registering-css-files https://filamentphp.com/docs/3.x/support/assets#registering-javascript-files Using a compiled version of Fullcalendar (if you use the node version of it) is possible too, simply load you app.js compiled with Vite or anything else. After that you have the full power to use the native interaction between PHP and Javascript with Livewire
Brian Kidd
Brian Kiddβ€’12mo ago
Thanks @jibaymcs for your response. Yes I’ve reviewed the documentation and have fullcalendar working in a widget using FilamentAsset but specifically what I’m asking is if I can use the β€œarg” parameter passed to the fullcalendar eventContent function and return dynamic HTML. Do you use the fullcalendar eventContent function in your custom widget?
JibayMcs
JibayMcsβ€’12mo ago
Oh, okay, let me check if I have a sample code for you
Solution
JibayMcs
JibayMcsβ€’12mo ago
Okay so I have something like this: Widget.php
use Filament\Widgets\Widget;
use Illuminate\Support\HtmlString;

class FullCalendarTest extends Widget
{
protected static bool $isLazy = false;

protected static string $view = 'filament.widgets.full-calendar-test';

public $events = [];

public function mount()
{
$this->events = [
[
'id' => 'test',
'title' => 'Brian Kidd Tests',
'start' => now()->format('Y-m-d'),
'extendedProps' => [
'description' => '<strong>Hello from Filament Discord !</strong>',
],
],

[
'id' => 'test',
'title' => 'Brian Kidd Tests Urgent',
'start' => now()->addWeek()->format('Y-m-d'),
'extendedProps' => [
'isUrgent' => true,
'description' => '<strong class="text-danger-600">Hello from Filament Discord !</strong>',
],
],
];
}
}
use Filament\Widgets\Widget;
use Illuminate\Support\HtmlString;

class FullCalendarTest extends Widget
{
protected static bool $isLazy = false;

protected static string $view = 'filament.widgets.full-calendar-test';

public $events = [];

public function mount()
{
$this->events = [
[
'id' => 'test',
'title' => 'Brian Kidd Tests',
'start' => now()->format('Y-m-d'),
'extendedProps' => [
'description' => '<strong>Hello from Filament Discord !</strong>',
],
],

[
'id' => 'test',
'title' => 'Brian Kidd Tests Urgent',
'start' => now()->addWeek()->format('Y-m-d'),
'extendedProps' => [
'isUrgent' => true,
'description' => '<strong class="text-danger-600">Hello from Filament Discord !</strong>',
],
],
];
}
}
resources/views/filament/widgets/full-calendar-test.blade.php
<x-filament-widgets::widget>
<x-filament::section>
<div id="calendar"></div>
</x-filament::section>
<script>
document.addEventListener('livewire:initialized', () => {

let calendarEl = document.getElementById('calendar');
let calendar = new FullCalendar.Calendar(calendarEl, {
initialView: 'dayGridMonth',
// @this.events retreive your 'public $events = [];' in your Widget php class
events: @this.events,

eventContent: function(arg) {
let italicEl = document.createElement('i')

if (arg.event.extendedProps.isUrgent) {
italicEl.innerHTML = arg.event.extendedProps.description + ' (urgent)'
} else {
italicEl.innerHTML = arg.event.extendedProps.description
}

let arrayOfDomNodes = [ italicEl ]
return { domNodes: arrayOfDomNodes }
}
});
calendar.render();
})

</script>
</x-filament-widgets::widget>
<x-filament-widgets::widget>
<x-filament::section>
<div id="calendar"></div>
</x-filament::section>
<script>
document.addEventListener('livewire:initialized', () => {

let calendarEl = document.getElementById('calendar');
let calendar = new FullCalendar.Calendar(calendarEl, {
initialView: 'dayGridMonth',
// @this.events retreive your 'public $events = [];' in your Widget php class
events: @this.events,

eventContent: function(arg) {
let italicEl = document.createElement('i')

if (arg.event.extendedProps.isUrgent) {
italicEl.innerHTML = arg.event.extendedProps.description + ' (urgent)'
} else {
italicEl.innerHTML = arg.event.extendedProps.description
}

let arrayOfDomNodes = [ italicEl ]
return { domNodes: arrayOfDomNodes }
}
});
calendar.render();
})

</script>
</x-filament-widgets::widget>
It's not a perfect solution I think, but you have something works πŸ™‚
JibayMcs
JibayMcsβ€’12mo ago
Blade injection works too.
[
'id' => 'test',
'title' => 'Brian Kidd Tests Urgent',
'start' => now()->addWeek()->format('Y-m-d'),
'extendedProps' => [
'isUrgent' => true,
'description' => Blade::render('test-content-injection'),
],
],
[
'id' => 'test',
'title' => 'Brian Kidd Tests Urgent',
'start' => now()->addWeek()->format('Y-m-d'),
'extendedProps' => [
'isUrgent' => true,
'description' => Blade::render('test-content-injection'),
],
],
resources/views/test-content-injection.blade.php
<p>Hello world !</p>
<p>Hello world !</p>
Hope you can work with this little tricks !
Brian Kidd
Brian Kiddβ€’12mo ago
Okay so you are including the html in the extended props - I like this idea and will give it a try. Thanks