Sessions is temporarily moving to YouTube, check out all our new videos here.

Introduction to Ember Power Calendar

Miguel Camba speaking at Ember London in February, 2017
Great talks, fired to your inbox 👌
No junk, no spam, just great talks. Unsubscribe any time.

About this talk

Ember Power Calendar is a complex calendar, which you can customize to your needs, e.g. highlight dates or have pop-ups appearing on the dates. It is part of the Ember Power Project, a set of components for Ember that aim to be reusable, and allow you to replace the parts that you don't want with your own components.


I've been building something lately. I built this thing like a year ago...and was the beginning of the Ember Power a set of components for Ember that aim to be pretty reusable and low-level enough to allow you to step in and replace the bits you don't want with your own components. After Ember-Power-Select, I found myself needing a calendar, and I created Ember-Power-Calendar. And, as a result of instructing some functionality for Ember-Power-Calendar I created the Basic-Dropdown. And the main philosophy between them is that, as you see, there is an "Addons" section here. Another one here. Well, the Addons section is for people who build something interesting on top of the add-on. They can publish meta-addons with a keyword. I can detect and include whatever they build that happens to be an Ember-Power-Select addon or an Ember-Power-Calendar addon. And it's nice that this inspires someone else to do the same approach. This is not by me. I just let them use the style. And it has also a few addons, like more...well, to integrate more things on top of the Leaflet, which is a calendar library. - [Audience] This is another Miguel? - Yes, it's another Miguel, but it's not me. I think some Miguel started a thing... - I told you not to stop calling these experimental friends. - Okay. I developed the calendar because I found myself needing pretty complex calendars. Calendars like this one where you need to highlight dates, you need to have pop-ups appearing on the dates. And this is what's [inaudible] what you could do with anything like Bootstrap Calendar, or Pick A Day, or the classical J collaboration we use. So, for building these kinds of things, I developed the Power-Calendar. And now I found myself needing the same thing floating in a box when you want to build a date picker. And I realized a date picker is more or less a calendar living inside a dropdown. That's the basic definition. So I created the Ember-Power-Datepicker. And it's exactly what you would expect. You take the one component of that [inaudible] one thing, which is the dropdown. You put the calendar inside. You wire two things together. And, actually, you have a pretty powerful and customizable datepicker you can use. I have some demo here. This is the code... I'm sorry, this is the demo. And this is the different styles. Nothing special. You can select dates. This is exactly the same thing you have... Cookbook... No, Docs. How to use it. This is the exact same component which happens to be inside a dropdown, and, actually, all the actions along the interface, it's identical to the one in the calendar. It just happens to be floating in a box. I created a few themes. This is a classical horrendous Bootstrap one. You have a pretty nice material-like design. - [Audience] Nice. - And what I want to show is that, actually, the code of this thing is this. - [Audience] Bigger. - Sorry. This is the entire code of the component. It's 20 lines. And this is because I'm merging the APIs of two components that do one thing and do it well into a single... Basically, all the code is in here. This is the template. You have the basic dropdown. You pass some options. You render the power calendar with some options. So, the power component just takes care of redirecting the proper option to the proper component inside. And both components use [inaudible] contextual components. So, in the end, what I get is a dropdown, a calendar. And with the with-helper and the hash-helper I just merge together with the ability of renaming things if there is a clash. I created the [inaudible] of the actions. So I have... The public API is like a merge of both APIs. It's a deep merge. And then I [inaudible] everything to the template. And the usage is... HBS... And this is the usage. You have the power-datepicker. You pass the options you expect to have. You deal the dropdown. The dropdown has a trigger. Inside the trigger, you can do whatever you want. So if you want to have an input, you have an input. If you want to have a div so you cannot type, you have a div. If you want to have, like in the example of... In my area, you're using some CSS framework like Bootstrap, for example. And you have this input with what they call an "input add-on," which is kind of a button that is functioned with the input. You don't need to decide if you want the button to be the thing you click to open the calendar. It's not a decision of the library. If you want this thing to open not when you click the trigger, like here...sorry, the input, in this example. But when you click a button next to the input, you put this thing outside. You say tagName="button" Choose a date. And now this thing here does nothing because this is the thing that opens the datepicker. And that's the thing. It's pretty low-level, but it allows you to build whatever you want on top using the APIs of these two components. And every option these components support, this merge of both APIs supports the same options. So you can have the disable days, you can replace the DOM of my example of the calendar, if you want... In this example, every calendar is a month. But you can have a calendar that is only a week. I don't care. You replace the thing in the middle that renders the dates. The logic is everything on the [inaudible] component. So as long as you use the public API object that has these options, has these actions... The actions is the public API you use to communicate with the dropdown. So, actually, if you don't want to use the trigger at all... So, this one... You don't even need to use this thing. You can do "button" and "onclick" you do "{{dp.actions.toggle}}." And I want this thing here. So I don't even need to use the components I provide. Everything is on the public API. So this...datepicker, actions toggle... Yeah, should be there. Ah, I know why. It has to have a specificity so it can...I mean, the dropdown has to know next to what it has to float. It has to... I don't remember the same action here, but this "{{dp.unique ID}}." Maybe that one? Actually, I can check the... Data, this thing. And see if it opens. I don't know. Believe me, it works. If you work this. So that's the idea. That's what I built. You can find it in here in the Repo, Ember-Power-Datepicker. I'm not very imaginative with names. And that's it. You can use it and let me know if you like it. - [Audience] You going to ask a question? - Yes. - [Audience] That can get quite funky. - Not so funky, I believe. Let me open this. - [Audience] Okay, groovy then. - So... This is the entire component. Basically, the red show the APIs, so it makes some sense for people who hasn't seen this thing. This is how you use the calendar. So you render the Power-Calendar. You give it... Depending on what you want to do, you give it a center. You give it a selected value. But the thing is, then you render the "calendar.nav" if you want. And the "calendar.days" also if you want. The nav, it's this thing here. And the days is degree of days. And if you want to customize how the days work, basically, if you don't pass a block, it's going to render a number. If you pass a block, it's going to jilt a day object. A day object is an object that contains a number, it contains a few utility classes like it's disabled. It's a few things you mjay want to use like the weight by example because you use it for iterating. And you render by example. In this example, if the weekday happens to be a Saturday or a Sunday, I have a strong with a clash of pink text. And I render Saturdays and Sundays on red. Or if I don't like Mondays, I remove Mondays from the calendar. And I don't, so... In this case, if I... What am I doing? Yes, if... Weekdays without Mondays or Wednesdays. And this is it. I remove the days I don't want. And I render a month with only Tuesday, Thursday... So, I remove Wednesdays as well because Wednesdays... I don't know. - [inaudible]. - Yes. You can pass your own components. So this is the same example as I instructed...this component into a thing so I can reuse. So I just pass the days component. And these ".days" now is this thing that I passed. You can customize the start of the week, as you can imagine. Show days around or not. So in this example, I am seeing the days before and after the month. But you can disable this. - [Audience] [inaudible]. - Minimum dates. So, in this case, you disable days before and after one date. So you can only select things on this range. Also, this thing. You can select the format of the calendar in the navigation. It's pretty much the same idea. If you pass a block, it's going to render that block. Otherwise, it's going to render the default behavior. The block, in this case, I just used "moment-format" from Member Moment to render whatever you want. And I format with this format. And this is what I show. It shows "Feb" instead of "February." Using the public API. I decide that I want to have instead of these arrow keys to go to the next or previous month, I want another button to go to the next or previous year. So I just build it. I use the "actions.calendar.moveCenter". And instead of doing 1 month, I do 12 months. So this goes to January, but this one goes to January 2016. Everything's on the public API. You can pass your own component. Which, again, is this thing instructed. So I pass my navigation component. It's this component. And I... Let's see... Everything's wired. And the way you... Even this one in here. I don't think I'm breaking any law by showing this thing. It's... And this is the... To see a really complex example. This is the move section template. This one, by example... It's the "booking-session-reschedule-module" template. This is it. This is a power-calendar. I have some classes. I select the... I move the... I have the "onSelect" and "selected" values because it's used outside the date. And then in the calendars, I decide I have a minimum date of today as a variable. I have a loading state because every time I change the month, I need to load every event that is going to happen the next month. This supports every [inaudible] task. So if from here you're entering a promise or a task, the position is going to have a loading state until this task is finished. And then it renders the next month or the previous month. And then, inside each day, I... Basically, this depends on my logic. But I have sessions. I group the sessions depending on what day they're happening. I group them whether or not they are confirmed sessions or pending sessions. So they are green or orange. And I have this component in here that is the day itself. And this anstract [inaudible]. But inside, if you look inside, this has a dropdown inside. Because when you click it, it opens the list of sessions happening this day. So that's it. It's yours to break, to mold to your will. to render strange things inside. to render circles, or pretty much anything. It's a block. Or it's a component. Replace my components by your own components, and you can create any calendar you want. - Yes, two calendars. Basically, you should... By example... I am going to close this thing. Days... This is the... Is this the datepicker? No. This is not the datepicker. This is the datepicker. So you see that in here I am rendering the days component. What happens if I render two? Because I can. I don't know if this is... I think it broke for a different reason. I'll undo all these things. Okay, render it again. I rendered two. So I have two of them. Now it's your task to put them side-to-side. And you need to wire these actions because these actions is up to you. So basically, what you would have to do... Let me duplicate this thing. - At the moment it's the same. That's the thing. Now you need to decide. This month is always one month ahead of this. Or two, or three. And when you click this one, you need to implement the logic to say when I click this, I move the date of this calendar, but I can never go past this one. Because [inaudible] this is the first one, this is the second one. If I move the center of one... When I arrive to a point where if I go to the previous month I would be on the same, you don't. You [inaudible] from the action and nothing happens. So this is going to be a default behavior on the datepicker I'm just starting. But it's up to you to wire things so... You have two calendars, and you wire things that... The calendars... The one on the right is never in the past in respect to the one on the left. Or a range, when you select a range in this one. Range selection. You have this and you select ranges. You have to say that the range starts in one calendar and ends in the other. But this is perfectly fine. You have a range. The range has a start and an end. And if a range starts in one calendar but ends in another one, the range is the same for both. And you will render range starting here and ending here. I just realized I'm not pointing at anything. Starting here, and ending it here. That's right. Let me see if it works. What is the... The right one? Yes. So, the range would expand three rows and then maybe here. But it's still in progress. I basically did it three days ago. So that's it.