I am doing a project using Nodejs for the backend, vanilla JS compiled with Parcel Bundler for the client side JS and PUG template engine to generate the views.
Note that I also use the FullCalendar v5 plugin. I don't think this is relevant as I feel this situation could happen without it, but still, it is the reason I encounter this problem at the moment.
Let's get straight to the point : I have a "main" parent function called initCalendar()
.
It initializes the calendar, creates the FullCalendar instance (along with all the calendars methods), sets it up depending on the configs given and renders it on the view. This function is the top level one of events.js
, the "main" function as I like to call it.
initCalendar()
is exported from events.js
using the export
keyword : export const initCalendar = () => { … }
.
After this, I coded the calendar proprietary functions, which allow me to perform whatever action I want based on the ones done on the calendar. Like eventClick()
for example, which executes whenever an event from the calendar is clicked, as its name suggests.
The point is, I created some functions in this eventClick()
function (which itself is in initCalendar()
), some of which I need to use in index.js
. Therefore the need to export them. Also, I can't move these functions outside of initCalendar()
scope, as I will loose important variables needed for my functions to run properly, and I would like to avoid using global variables.
My custom functions are nested like so : initCalendar() -> eventClick() -> myFunction()
("main" exported parent function -> intermediate calendar function -> my functions (to be exported)).
In case you're wondering why I have to do it this way, it is to keep the same workflow I have been using so far for all the client side JS of the project, trying to do it "the Parcel way". I have lots of exported functions that are imported in index.js
from many different files, but this problem only got here when I included FullCalendar to the mix.
So the solution I found for now is to export my functions directly from eventClick()
, using the exports
keyword this time : exports.myFunction = myFunction
. Doing this, I can then import them in index.js
and continue to use the same workflow I used for all the client side JS (remember, compiled with Parcel Bundler).
What do you think about this "technique" ? Isn't it bad practice to export a child function from an already exported parent function ?
It seems quite hacky to me and I don't really like that… But I didn't find any better solution yet. Maybe someone could give me some insight on wether or not it is OK to do so and if not, how to solve the problem another way ? I thought maybe using callback functions, but I can not get it to work this way.
------- EDIT : Some code -------
Here is some code. I tried to cut it to the minimum, because the code of the clickEvent()
function is literally hundred of lines long, and the one for FullCalendar is even bigger.
events.js
: As you can see, the eventClick()
function first opens a Modal which contains all the event info (that I didn't write because not relevant) and one button to delete the clicked event.
This is this button that should have his listener
set from index.js
calling the "exported child function" removeEvent()
on a click
event, to delete the associated event from DB and calendar.
There is other functions in the same style in there but this one should be enough to see what I'm talking about.
// events.js
// … All the es6 imports : { Calendar } - { Modal } - axios; etc …
// As you can see, if I try to export the removeEvent() function from here,
// it would work as exporting goes but I won't have the Modal instance of
// `eventInfoModal` used in `.then()`. Same thing with `const calendar`,
// because they would not be in the scope of `initCalendar()`.
// Therefore I won't be able to call the functions I do on them in `.then()`
export const initCalendar = () => {
const calendarEl = document.getElementById('calendar');
const calendar = new Calendar(calendarEl, {
// … Ton of code to config FullCalendar, import the events, other calendar functions etc…
eventClick: function(eventInfo) {
const eventId = eventInfo.event.id;
const infoModalContainer = document.getElementById('event-info-modal');
// Modal created from an imported class
const eventInfoModal = new Modal(
infoModalContainer,
this.el
);
eventInfoModal.init();
// … Lots of code to populate the modal with the event data, buttons etc …
// So the point here is to call this function from index.js (code of index.js below)
function removeEvent() {
if (confirm('Êtes-vous sûr de vouloir supprimer ce RDV ?')) {
deleteEvent(eventId)
.then(() => {
eventInfoModal.close();
calendar.refetchEvents();
});
}
}
// The "exported child function" I was talking about
exports.removeEvent = removeEvent;
// Then other functions defined and exported the same way, to be used just like removeEvent() in index.js
});
calendar.render();
// Function called from removeEvent() in eventClick() above, just doing an axios DELETE request, no need to write it
async function deleteEvent(eventId) {
}
};
index.js
: Here I import all the exported functions from the other files (only showing the one we are talking about obviously) and try to group and set my listeners together by view or "by category", listeners that will then call the corresponding functions imported from the other files, to execute the needed actions.
// index.js
// … All the es6 imports, including :
import { removeEvent } from './events';
const userEventsPage = document.getElementById('user-events');
if (userEventsPage) {
const deleteEventBtn = document.getElementById('delete-event');
userEventsPage.addEventListener('click', evt => {
if (evt.target === deleteEventBtn) {
removeEvent();
}
});
}
Thank you very much