I’ve been working on a calendar CLNDR.js using moment.js and a bit of Underscore.js building an array of JSON objects to populate the calendar with events, working good so far.
One issue I’m having right now is that everyday/square on the calendar will fire my modal popup regardless if I have events or not.
Wondering where and how I can fix the code so the modal will show only on the days with the events attached?
The modal data-toggle is attached to every day, but how do I tell the click event to ignore the empty days?
var myCal = $('#calendar').clndr({
constraints: {
startDate: '2016-08-06',
endDate: '2016-12-16'
},
template: $('#calendar-template').html(),
weekOffset: 1,
events: events,
startWithMonth: moment(),
clickEvents: {
click: function (target) {
if(target.events.length) {
var body = '';
body += '<div class="modal-dialog"><div class="modal-content">',
body += '<div class="modal-header">',
body += '<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">x</span></button>',
body += '<h4 class="modal-title">Events on '+ target.date.format('MMMM Do YYYY')+'</h4></div>',
body += '<div class="modal-body">'
// loop through the events, making a <div> for each with info
for(var i = 0; i < target.events.length; i++) {
body += target.events[i].startTime+' - '+target.events[i].endTime+'<br>',
body += '<div class="event">' + target.events[i].title + '</div>',
body += target.events[i].location + '<br>';
}
body += '</div><div></div>';
//console.log(target.events);
$("#events-list-modal").html(body);
}
},
}
});
I’m also wondering maybe I should display the var body on the page using underscore like the other code, looking a bit messy, what do you think?
I would just filter the events to remove any older than the current date, before initializing the calendar.
Yeah, as you’ve already got underscore loaded anyway, you might as well use it here too and pull out all the markup into a template. Then your click handler will end up looking something like this:
if(target.events.length) {
var body = eventTpl({
date: target.date.format('MMMM Do YYYY'),
events: target.events
});
$("#events-list-modal").html(body);
$("#events-list-modal").modal('show');
}
Thanks for detailed explanation and fork looks so easy now ha.
I didn’t realise we needed multiple templates and stuff, gives me scope for moving forward with extra templates now I understand. Much cleaner now separating our code and data
I’m also working on some extra functionality for this calendar, as you can see the different colors, this represents different categories which I’ll be filtering… though another thread once up and running if I need help.
I’ve been using underscore past couple of weeks just wondering if this is something you use yourself? What do you think of underscore as a templating framework? What do you use?
Reason I ask - I read an article today talking about underscore is dead with the arrival of ES6
What your view on this? And do you use Babel (religiously)?
Yeah I’ve been using lodash on a project lately. Whether I’d use it for templating would depend: if there’s a limited amount of markup to be generated and I’m already including underscore then sure, but in other situations I’ve used something like mustache/handlebars (I prefer the syntax).
Regarding Derick Bailey’s article, I think he has a point in that you don’t want to be including a whole lib like underscore or lodash if all you’re going to use are some basic array methods like map and filter. Where those libraries shine is with more heavy duty data manipulation, because it’s really easy to chain together a bunch of simple functions to do some very complex things.
As for ES6/Babel, I’m starting to get into that more. I have a project at the moment where I’m forcing myself to use ES6 syntax/features where possible so I can become fully conversant with them.
Yes I did look at handlebars, so many different libraries
It usually boils down to what the person is most comfortable with, as you mention yourself, handlebars, or best fit for purpose.
Thanks for the link, I had a browse through good write up, advanced stuff!
I’m still a JS novice so a little over my head, though nice to see what else can be done, still learning about things like currying and using operations etc.
That’s another reason I asked about ES6, might dive straight into ES6 than coding in older syntax, something to think about. Though maybe best get the fundamentals before jumping the gun.
I look forward to when I can do this
As for ES6/Babel, I’m starting to get into that more. I have a project at the moment where I’m forcing myself to use ES6 syntax/features where possible so I can become fully conversant with them.
And one last question which I came across today, if you get a chance for a quick look fretburner
As things stand, on clicking a day in the calendar, the modal pops up and displays all the events for that day works good as you know.
But now, I need to create another instance of this calendar, but this time only show the modal for each event and not all events. Basically, only allow each event to be clicked and not the full day.
I was trying today though couldn’t figure out how to remove _each and get the details for each event?
That’s a bit trickier, because it doesn’t look as though the calendar plugin provides a way to identify which event was clicked. The click handler you set only seems to receive a collection of events for the selected day.
The best way so far that I could think of to get around it is to listen for click events on the event divs themselves.
To do that, first you’ll need to amend the calendar template to add a data attribute to each event div with its index in the events array:
and then, after initializing the calendar plugin, add an event listener to handle any click events on divs with the event-marker class:
$('#calendar').on('click', '.event-marker', function(event) {
var id = $(this).data('eventId');
var event = events[id];
// Now you can render your modal content and display it
})
Great timing.
Been working on this for past 3-4 hours… close to dismantling my computer ha
That’s a bit trickier, because it doesn’t look as though the calendar plugin provides a way to identify which event was clicked. The click handler you set only seems to receive a collection of events for the selected day.
This is what was causing the main problem. The only feature out of the box is clicking the day itself and showing all events. As you’ve realised, you can’t click the events separately.
Tried everything… I’ll give this a shot and let you know how things go!
click: function (target) {
if(target.events.length) {
var body = eventTpl({
date: target.date.format('MMMM Do YYYY'),
events: target.events
});
//console.log(target.events);
$("#events-list-modal").html(body);
$('#calendar').on('click', '.event-marker', function(event) {
var id = $(this).data('eventId');
var event = events[id];
$("#events-list-modal").modal('show');
})
}
},
I’ll be changing some of the classes to fit the new instance as styling is slight different, this won’t be a problem now we have everything in working order.
And incase your wondering.
The first instance we worked on is a mini calendar and this, second instance will be a bigger version with more focus on each event.
I’ll draw this thread to a close, been a busy few nights and sure you’ve had enough of calendars for one week
As mentioned previous, some more features to work on which I’ll create a new thread if I need any assistance though some good examples here.
Doh! Yes indeed… the index relates to the selected day’s array of events, not the array of all events.
(Edit: Just to clarify, that was me making a silly mistake. What can I say… it was late and I was tired )
So, what we can do is get the event we want by title, so we’d need a function to handle that:
function getEventByTitle(title) {
var event = events.filter(function(ev) {
return ev.title === title
});
return (event.length > 0) ? event[0] : null;
}
What we’re doing here is just filtering the array to return the events with a matching title (which is hopefully unique). Filter returns an array, so we’ll check if it’s not empty and return the first element, else return null.
Next we need to change the event click handler to call this new function:
$('#calendar').on('click', '.event-marker', function(event) {
var title = $(this).data('eventTitle');
var event = getEventByTitle(title);
if (event) {
var body = eventTpl({
event: event
});
$("#events-list-modal").html(body);
$("#events-list-modal").modal('show');
}
});
If we get back null from getEventByTitle() then we don’t do anything. We should always get something back, but it’s a good idea to check anyway.
Lastly we need to tweak the calendar template, to set a data attribute with the event’s title instead of the ID: