Reputation: 87
I'm having quite a tussle with my code. I've deployed FullCalendar v5 as a Vue 3 component inside a laravel 9 site using Breeze for authentication and Inertia for speedy rendering. I have the Calendar/Pages/Index.vue displaying the calendar and updating events on the calendar with modals from the example, but I cannot manage to get the modals to create events in the database, nor get the events from the database table to display on the calendar. I'm trying to avoid Ajax and use axios to retrieve a JSON feed.
Here's the part of my controller that creates the JSON feed:
public function showEvents(Request $request) {
$event = Event::get(['title','acronym','city','venue','value','start','end']);
return response()->json(["events" => $event]);
}
Here's what the JSON feed returns:
{"events":[{"title":"Test","acronym":"TST","city":"Denver","venue":"Big Venue","value":"$0","start":"2022-10-25 00:00:00","end":"2022-10-28 00:00:00"}]}
And here's my rather massive Calendar/Index.vue:
<template>
<head title="Dashboard" />
<BreezeAuthenticatedLayout>
<template #header>
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
Resource Calendar Timeline
</h2>
</template>
<div class="py-12">
<div class="max-w-10xl mx-auto sm:px-6 lg:px-8">
<div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
<div class="p-12 bg-white border-b border-gray-200">
<!--start calendar-->
<div class='demo-app'>
<div class='demo-app-main'>
<FullCalendar
class='demo-app-calendar'
:events="calendarEvents"
:options='calendarOptions'>
<template v-slot:eventContent='arg'>
<b>{{ arg.timeText }}</b>
<i>{{ arg.event.title }}</i>
</template>
</FullCalendar>
</div>
</div>
<!--end calendar-->
</div>
</div>
</div>
</div>
</BreezeAuthenticatedLayout>
</template>
<!--start calendar-->
<script setup lang='ts'>
import BreezeAuthenticatedLayout from '@/Layouts/AuthenticatedLayout.vue';
import { head, Link } from '@inertiajs/inertia-vue3';
import '@fullcalendar/core/vdom'; // solves problem with Vite
import { defineComponent } from 'vue';
import FullCalendar, { CalendarOptions, EventApi, DateSelectArg, EventClickArg } from '@fullcalendar/vue3';
import dayGridPlugin from '@fullcalendar/daygrid';
import timeGridPlugin from '@fullcalendar/timegrid';
import listPlugin from '@fullcalendar/list';
import interactionPlugin from '@fullcalendar/interaction';
import axios from 'axios';
</script>
<script lang='ts'>
const Demo = defineComponent({
components: {
FullCalendar,
},
data() {
return {
// trying to pull events from DB json -->>
eventSources: [{
url: 'https://l9-v3-breeze-crud.ddev.site/show-events', // use the `url` property
color: 'yellow', // an option!
textColor: 'black' // an option!
}],
calendarEvents: [{
events(title, start, end, callback) {
axios.get('https://l9-v3-breeze-crud.ddev.site/show-events').then(res => {
callback(res.data.events)
})
},
failure: function() {
alert('there was an error while fetching events!');
},
color: 'red',
textColor: 'white',
}],
//end events pull from DB -->
calendarOptions: {
plugins: [
dayGridPlugin,
timeGridPlugin,
listPlugin,
interactionPlugin // needed for dateClick
],
headerToolbar: {
left: 'promptResource prev,next today',
center: 'title',
right: 'dayGridMonth,timeGridWeek,timeGridDay,listMonth'
},
},
initialView: 'dayGridMonth',
events: this.getEvents,
editable: true,
selectable: true,
selectMirror: true,
dayMaxEvents: true,
weekends: true,
select: this.handleDateSelect,
eventClick: this.handleEventClick,
eventsSet: this.handleEvents
} as CalendarOptions,
currentEvents: [] as EventApi[],
}
},
methods: {
getEvents(info, successCallback, failureCallback) {
events(start, end, timezone, callback) {
axios.get('http://localhost:8000/show-events').then(res => {
callback(res.data.eventList)
})
})
},
handleWeekendsToggle() {
this.calendarOptions.weekends = !this.calendarOptions.weekends // update a property
},
handleDateSelect(selectInfo: DateSelectArg) {
let title = prompt('Please enter a new title for your event')
let calendarApi = selectInfo.view.calendar
calendarApi.unselect() // clear date selection
if (title) {
calendarApi.addEvent({
id: createEventId(),
title,
start: selectInfo.startStr,
end: selectInfo.endStr,
allDay: selectInfo.allDay
})
}
},
handleEventClick(clickInfo: EventClickArg) {
if (confirm(`Are you sure you want to delete the event '${clickInfo.event.title}'`)) {
clickInfo.event.remove()
}
},
handleEvents(events: EventApi[]) {
this.currentEvents = events
},
}
})
export default Demo
</script>
<style lang='css'>
h2 {
margin: 0;
font-size: 16px;
}
ul {
margin: 0;
padding: 0 0 0 1.5em;
}
li {
margin: 1.5em 0;
padding: 0;
}
b { /* used for event dates/times */
margin-right: 3px;
}
.demo-app {
display: flex;
min-height: 100%;
font-family: Arial, Helvetica Neue, Helvetica, sans-serif;
font-size: 14px;
}
.demo-app-sidebar {
width: 300px;
line-height: 1.5;
background: #eaf9ff;
border-right: 1px solid #d3e2e8;
}
.demo-app-sidebar-section {
padding: 2em;
}
.demo-app-main {
flex-grow: 1;
padding: 3em;
}
.fc { /* the calendar root */
max-width: 1200px;
margin: 0 auto;
}
.fc-day-today
{
background-color: var(--fc-today-bg-color, rgba(255, 220, 40, 0.15));
}
.fc-day-sat, .fc-day-sun
{
background-color: var(--fc-today-bg-color, rgba(255, 100, 40, 0.15));
}
</style>
I'm stumped! Either I pull an empty array for events with
events[]
or I get a 500 error denoting that "Module source URI is not allowed in this document: “http://[::1]:5173/resources/js/Pages/Calendar/Index.vue" when I try the axios.get URL
and, not matter what I try, I can't seem to get it to pull the 'calendarEvents' options from
calendarEvents: [{
events(title, start, end, callback) {
axios.get('https://l9-v3-breeze-crud.ddev.site/show-events').then(res => {
callback(res.data.events)
})
},
failure: function() {
alert('there was an error while fetching events!');
},
color: 'red',
textColor: 'white',
}],
Additional Information: I've been continuing to look for a solution and found several online demo's that resolve the issue at hand, but none with my particular project dependencies. Being a newbie at this, I'm just not certain on how to merge the code. In particular, the structure of the Calendar/Index.vue file taken from the http://fullcalendar.io Vue3 and TypeScript demo here https://github.com/fullcalendar/fullcalendar-example-projects/tree/master/vue3-typescript And in the app.js file from this demo https://www.positronx.io/how-to-display-events-in-calendar-with-laravel-vue-js/
My app.js is complicated by the installation of Ziggy and Inertia and I'm not certain how to construct the Vue rather than a blade. Here's my app.js:
import './bootstrap';
import '../css/app.css';
//import { ZiggyVue } from 'ziggy-vue';
//import route from 'ziggy';
import { createApp, h } from 'vue';
import { ZiggyVue } from '../../vendor/tightenco/ziggy/dist/vue.m';
import { createInertiaApp } from '@inertiajs/inertia-vue3';
import { InertiaProgress } from '@inertiajs/progress';
import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers';
const appName = window.document.getElementsByTagName('title')[0]?.innerText || 'Laravel';
createInertiaApp({
title: (title) => `${title} - ${appName}`,
resolve: (name) => resolvePageComponent(`./Pages/${name}.vue`, import.meta.glob('./Pages/**/*.vue')),
setup({ el, app, props, plugin }) {
return createApp({ render: () => h(app, props) })
.use(plugin)
.use(ZiggyVue, Ziggy)
.mount(el);
},
});
InertiaProgress.init({ color: '#4B5563' });
Upvotes: 1
Views: 716
Reputation: 87
Ok, I figured out how to use axios to retrieve events from the JSON feed. The issue wasn't in the app.js routes, but rather in the actual Vue component itself.
Previously unmentioned, here is the route that constructs the JSON feed of events:
Route::get('show-events', [CalendarController::class, 'showEvents']);
Here's the part of my controller that generates that JSON feed for events from the database:
public function showEvents(Request $request) {
$event = Event::get(['title','acronym','city','venue','value','start','end']);
return response()->json(["events" => $event]);
And here's the method part of the Vue component that retrieves events from the JSON feel and publishes them to the calendar:
methods: {
getEvents() {
axios.get('show-events')
.then(response => {
this.calendarOptions.events = response.data.events;
});
},
Upvotes: 0