Comments (29)
Short answer: not easy right out of the box, but certainly possible.
Long answer: CLNDR is organized around the idea of a current month, however if you want to keep track of weeks, you could start with something like this:
clndr = $('.cal').clndr({
template: $('#template-calendar').html(),
extras: {
currentWeek: 0
},
doneRendering: function() {
$('.cal .next-week').click( function() {
console.log('next week');
clndr.options.extras.currentWeek += 1;
clndr.render();
});
$('.cal .previous-week').click( function() {
console.log('previous week');
clndr.options.extras.currentWeek -= 1;
clndr.render();
});
}
});
Where your template looks something like this:
<div class="clndr-controls">
<div class="previous-week">‹</div>
<div class="month"><%= month %></div>
<div class="next-week">›</div>
</div>
<div class="clndr-grid">
<div class="days-of-the-week">
<% _.each(daysOfTheWeek, function(day) { %>
<div class="header-day"><%= day %></div>
<% }); %>
<div class="days">
<% for(var i = extras.currentWeek * 7; i < extras.currentWeek * 7 + 7; i++) { %>
<div class="<%= days[i].classes %>" id="<%= days[i].id %>"><%= days[i].day %></div>
<% } %>
</div>
</div>
</div>
We're using the extras
option to keep track of an additional variable, and we're using the doneRendering
function to apply our own event handlers to our arrows. This example will break if you advance past the current month, so you'll also have to keep track of how many weeks there are in a given month. If you exceed that number, you'll have to call clndr.next()
which will advance you to the next month. I'll leave that part to you!
Hope that helps a bit.
from clndr.
Hi @kylestetz, thank's for that, I didn't find how to get the current year & month in order to apply moment('2012-02', 'YYYY-MM').daysInMonth();
EDIT: I had the 1.0.4 version, I just updated to 1.0.6 and it seams OK with:
console.log(clndr.month.daysInMonth());
Regards :)
from clndr.
Great! When you get it working it would be awesome if you could post your code here, or link to it in a gist or something, so other people can benefit from it. I'm happy to include it in a future version of the docs as well.
from clndr.
I messed up, I understood "days in month" and you said "keep track of how many weeks there are in a given month".
I'm searching how to know that...
from clndr.
Am I on the right way?
$('#test .clndr-next-button').click(function() {
if(test.options.extras.currentWeek < 4) {
test.options.extras.currentWeek += 1;
} else {
test.options.extras.currentWeek = 0;
test.next();
}
test.render();
});
The 4
must be a variable right?
from clndr.
Yes, very close, and the 4
should most definitely be a variable. To figure out the number of weeks in a month, try this out:
Math.ceil( clndr.month.daysInMonth() / 7 )
...which takes the days in the month, divides by seven to get the month's duration in weeks, and rounds up to a whole number.
from clndr.
Hum thank's but I get an error when the month has to change.
/* Call the CLNDR plugin */
var test = $('#test').clndr({
template: $('#tpl').html(),
events: events,
showAdjacentMonths: false,
extras: {
currentWeek: 0
},
clickEvents: {
click: function(target) {
},
onMonthChange: function(month) {
}
},
doneRendering: function() {
$('#test .clndr-next-button').on('click', function() {
var days_in_month = Math.ceil(test.month.daysInMonth() / 7);
if(test.options.extras.currentWeek < days_in_month) {
test.options.extras.currentWeek += 1;
} else {
test.options.extras.currentWeek = 0;
test.next();
}
test.render();
});
$('#test .clndr-previous-button').on('click', function() {
var days_in_month = Math.ceil(test.month.daysInMonth() / 7);
if(test.options.extras.currentWeek > 0) {
test.options.extras.currentWeek -= 1;
} else {
test.options.extras.currentWeek = days_in_month;
test.back();
}
test.render();
});
}
});
If I replace days_in_month
by 4
it's ok.
days_in_month
outputs 5
EDIT: The error is: "Uncaught TypeError: Cannot read property 'classes' of undefined"
from clndr.
I think the problem is that you are starting with currentWeek: 0
, which means that it is zero-indexed, but you are counting up to currentWeek == days_in_month
, when you should be counting up to currentWeek == (days_in_month - 1)
. To illustrate:
doneRendering: function() {
$('#test .clndr-next-button').on('click', function() {
// instead of days_in_month, you might want to call this one weeks_in_month (I was confused by this at first)
var weeks_in_month = Math.ceil(test.month.daysInMonth() / 7);
if(test.options.extras.currentWeek < weeks_in_month - 1) {
test.options.extras.currentWeek += 1;
} else {
test.options.extras.currentWeek = 0;
test.next();
}
});
}
Does that make sense?
from clndr.
You're right, what about: var weeks_in_month = Math.ceil(test.month.daysInMonth() / 7) - 1;
?
from clndr.
Yep, that works.
from clndr.
I've updated the first post with the right answer.
Huge thank's!
Regards
from clndr.
Awesome, thanks for sharing!
from clndr.
Hey!
I would like to start my week view with the current week. So I tried:
extras: {
currentWeek: moment().weekday() - 1
},
But it starts at week 4, one week more... Wtf... I don't think that the right answer is:
extras: {
currentWeek: moment().weekday() - 2
},
EDIT: Moreover, there is a issue with my week view and the showAdjacentMonths option.
When in a week you have the last part of the month and the first part of the next month, when you click to next button, the displayed month is October (ok but the 7 days does not change).
Example:
September:
October (just clicked on next):
Regards
from clndr.
Regarding your issue with the next button, it could be that you're using the class clndr-next-button
, which is automatically tied to the 'next month' event handler. Try giving those arrows different classes that aren't used internally by clndr.
You're going to have to do some math to figure out the current week. Something like
Math.floor( Math.ceil(moment().daysInMonth() / 7) * (moment().date() / moment().daysInMonth()) )
although that doesn't take into account the offset that can occur if a week starts on a weekday. Sorry I can't be of more help at the moment with this, but the idea is to figure out how far you are into the month as a percentage of the weeks in the month.
from clndr.
Unfortunately I don't use clndr's classes.
I'm also terrible in math. Your calculation outputs 4. We are September 28 and the showed week is "29...5". It's not ok.
If you need to reproduce my use case:
HTML
<script type="text/template" id="cal_template">
<table class="table table-bordered">
<thead>
<tr>
<th>
<button type="button" class="btn btn-default btn-xs previous-btn">
<i class="glyphicons chevron-left"></i>
</button>
</th>
<th class="text-center text-uppercase" colspan="5"><%= month %> <%= year %></th>
<th class="text-right">
<button type="button" class="btn btn-default btn-xs next-btn">
<i class="glyphicons chevron-right"></i>
</button>
</th>
</tr>
<tr>
<% for(var i = extras.currentWeek * 7; i < extras.currentWeek * 7 + 7; i++) { %>
<th class="text-center" id="<%= days[i].id %>">
<%= daysOfTheWeek[days[i].date.day()] %>. <%= days[i].day %>
</th>
<% } %>
</tr>
</thead>
</table>
</script>
Javascript
/* Call the CLNDR plugin */
var iphone_cal = $('#iphone_cal').clndr({
template: $('#cal_template').html(),
extras: {
currentWeek: Math.floor( Math.ceil(moment().daysInMonth() / 7) * (moment().date() / moment().daysInMonth()) )
},
showAdjacentMonths: true,
doneRendering: function() {
/* Next button handler */
$('.next-btn').on('click', function() {
/* Get numbers of weeks in the month */
var weeks_in_month = Math.ceil(iphone_cal.month.daysInMonth() / 7) - 1;
if(iphone_cal.options.extras.currentWeek < weeks_in_month) {
/* Increase the week count */
iphone_cal.options.extras.currentWeek += 1;
} else {
/* Reset the week count */
iphone_cal.options.extras.currentWeek = 0;
/* Go to next month */
iphone_cal.next();
}
iphone_cal.render();
});
/* Previous button handler */
$('.previous-btn').on('click', function() {
/* Get numbers of weeks in the month */
var weeks_in_month = Math.ceil(iphone_cal.month.daysInMonth() / 7) - 1;
if(iphone_cal.options.extras.currentWeek > 0) {
/* Decrease the week count */
iphone_cal.options.extras.currentWeek -= 1;
} else {
/* Reset the week count */
iphone_cal.options.extras.currentWeek = weeks_in_month;
/* Go to previous month */
iphone_cal.back();
}
iphone_cal.render();
});
}
});
I appreciate your help. ;)
from clndr.
Ha, this is interesting. That September to October switch you're seeing is not a bug. It's happening because the last week of September (which includes the 29th and 30th) is the same week as the first week in October (which includes the 1st to the 5th). If you add <%= days[i].classes %>
to your loop so that your <th>
's look like this:
<th class="text-center <%= days[i].classes %>" id="<%= days[i].id %>">
<%= daysOfTheWeek[days[i].date.day()] %>. <%= days[i].day %>
</th>
and, in your stylesheet, give the class .adjacent-month
gray text color or opacity: 0.5;
or something, you will see what I mean.
So how do we get around this? It turns out to be pretty simple, with one caveat. Change all of the Math.ceil
s to Math.floor
(three altogether). What this does is round down instead of up when counting the number of weeks, meaning that the overlap (the last week of September transitioning to the first week in October, even though they are exactly the same week) doesn't happen.
The caveat: the month name isn't quite right, since even though tomorrow is September 29th, it's going to read 'October 2013' because October starts during next week. The solution here just requires a bit of design. Since you are showing a week and not a month, perhaps showing the month name isn't the right way to go. Instead, I would suggest showing something like '9/29 - 10/5' or 'September 29th - October 5th', which you can do in your template like this (this code would replace where you're currently calling the month name):
<th class="text-center text-uppercase" colspan="5">
<%= days[extras.currentWeek * 7].date.format('M/D/YY') %> - <%= days[extras.currentWeek * 7 + 6].date.format('M/D/YY') %>
</th>
I used our currentWeek
variable again to grab the first and last day of the current week, calling .format()
on the date field (which is just a moment.js object) of each day.
I would say you are nearing the finish line on this one!
from clndr.
Hey! Very nice for the date range, good idea, it works.
Still not OK for the current_week at beginning. It shows me 22 to 28 september and we are on 29. What the hell is that! :)
Bests
from clndr.
Damn, I admire your patience here. I discovered a few more weird edge-case bugs playing around with it some more. I ironed them out (and fixed the currentWeek issue) and I'll just share my code because I can't quite explain it all:
$( function() {
function weeksInMonth(month) {
return Math.floor((month.daysInMonth() + moment(month).startOf('month').weekday()) / 7);
}
var iphone_cal = $('.cal').clndr({
template: $('#cal_template').html(),
extras: {
currentWeek: Math.ceil( weeksInMonth( moment() ) * ( moment().date() / moment().daysInMonth() ) )
},
showAdjacentMonths: true,
doneRendering: function() {
/* Next button handler */
$('.next-btn').on('click', function() {
/* Get numbers of weeks in the month */
var weeks_in_month = weeksInMonth(iphone_cal.month) - 1;
if(iphone_cal.options.extras.currentWeek < weeks_in_month) {
/* Increase the week count */
iphone_cal.options.extras.currentWeek += 1;
iphone_cal.render();
} else if(iphone_cal.options.extras.currentWeek > weeks_in_month) {
/* If we started at the last week of the month, we want to skip over currentWeek = 0 */
iphone_cal.options.extras.currentWeek = 1;
iphone_cal.next();
} else {
/* Reset the week count */
iphone_cal.options.extras.currentWeek = 0;
/* Go to next month */
iphone_cal.next();
}
});
/* Previous button handler */
$('.previous-btn').on('click', function() {
/* if we're just counting down we don't need to know the weeks in the month... */
if(iphone_cal.options.extras.currentWeek > 0) {
/* Decrease the week count */
iphone_cal.options.extras.currentWeek -= 1;
iphone_cal.render();
}
/* however if we've crossed 0, we need weeks_in_month to reflect LAST month
before clndr has had a chance to go back. */
else {
var weeks_in_month = weeksInMonth( moment(iphone_cal.month).subtract('month', 1) ) - 1;
/* Reset the week count */
iphone_cal.options.extras.currentWeek = weeks_in_month;
/* Go to previous month */
iphone_cal.back();
}
});
}
});
});
In going forward and backward, I noticed that the way we set up the numbers we were assuming that the first & last weeks of two months always overlap (which is not the case!). So I added an if statement to the next handler that takes care of this, and I messed around with the previous handler to take care of this in reverse. As far as I can tell (!!!) this is working correctly. Who knew it was so complicated!
Once we are sure that this is definitely working, I'd really like to make a JSFiddle out of this and share it in the docs so that anyone else looking to do this can build off of our trial-and-error. If that's cool with you.
from clndr.
- "Who knew it was so complicated!"
- "Me! :)"
Very cool it seems ok, I hope it's my last post here!
Thank you kyle.
from clndr.
Hi kyle, it was ok yesterday about showing the current week. Today it's not ok. It shows me OCTOBER 06, 2013 - OCTOBER 12, 2013...
Bests
EDIT: using 1.0.7
I replaced ceil() to floor() there:
extras: {
currentWeek: Math.floor(self.weeksInMonth(moment()) * (moment().date() / moment().daysInMonth()))
},
It's ok for today...
from clndr.
Ok dude, this is passing all the tests I can throw at it. I switched the math up to try and get more stable numbers. Long story short, we're now getting the day of the week as a fraction of the number of weeks * 7, rather than as a fraction of the days in the month.
Change your extras.currentWeek
to this:
extras: {
currentWeek: Math.floor( ( ( (moment().date() + moment().startOf('month').weekday() ) - 1 ) / ( weeksInMonth(moment() ) * 7) ) * weeksInMonth( moment() ) )
},
My test consisted of changing my computer's date and refreshing the page (a million times).
from clndr.
Yeah seems ok. Thank you for everything. This schedule will be used daily by my users (internally). I'll let you know for each potential problem.
Regards
from clndr.
Hey guys,
I just came across your solution and made a tiny jsfiddle to play around: http://jsfiddle.net/6f3nZ/1/
You're calculating the weeks in month, but it always should return 4. (Maybe because I'm using an weekOffset: 1 the -1 isn't necessary anymore).
A thing that bugs me is that you have to press next twice in months where the last two weeks appear in the next month again. According to the example and current date, the next occurance is in Week 31. As July contains weeks 27-32 and August weeks 31-36, there is an overlap of 3 weeks.
I couldn't find a way how to calculate this misbehave to simply call .next() one week earlier to overcome this.
Maybe one of you guys has an idea....
from clndr.
Hey @80leaves, there is a new branch of clndr with a feature that solves this problem. See #72 for details! I have not had much time of late to finish the branch up, but apart from some small API bugs the intervals branch is useable.
from clndr.
wow thanks for the fast reply, I haven't seen that one, time to check it out ;)
from clndr.
Yep, let me know how it works out for you!
from clndr.
I am facing issue with the previous and next. Please find the my code below
clndrData = $chooseDate.clndr({
// template: $('script#bookMeClndrTemplate').html(),
template: $('script#clndr_template').html(),
constraints: {
startDate: currentDate.format('YYYY-MM-DD')
},
ignoreInactiveDaysInSelection: true,
trackSelectedDate: true,
showAdjacentMonths: true,
ready: function () {
if (_.isNull(slotsData)) {
self.updateAvailableDays(currentDate, pkg, self, this, true);
} else {
self.onMonthSlotsGetSuccess(slotsData, currentDate, pkg, this, monthsAhead);
}
},
clickEvents: {
click: function (target) {
if (!$(target.element).hasClass('inactive') && !$(target.element).hasClass('empty')) {
self.updateSelectedDate(target.date, pkg, self, this);
//$chooseDate.hide();
//$('#' + self.breakpoint + '-choose-time-' + pkg.id).show();
}
},
onMonthChange(momentObj) {
this.options.extras.availableSlots = [];
this.render();
//var selfCalender=this;
//selfCalender.month=momentObj.month();
if (currentDate.year() === momentObj.year() && currentDate.month() === momentObj.month()) {
momentObj = currentDate;
}
//self.updateAvailableDays(momentObj, pkg, self, this, false);
}
},
extras: {
availableSlots: [],
currentWeek: Math.floor( ( ( (moment().date() + moment().startOf('month').weekday() ) - 1 ) / ( self.weeksInMonth(moment() ) * 7) ) * self.weeksInMonth( moment() ) )
},
doneRendering: function() {
var selfCalender=this;
console.log(selfCalender.month)
console.log(selfCalender.month.weeks_in_month)
/* Next button handler */
$('.book-me-week-calender .clndr-next-button').on('click', function() {
/* Get numbers of weeks in the month */
/* var weeks_in_month = Math.floor(selfCalender.month.daysInMonth() / 7) - 1;
if(selfCalender.options.extras.currentWeek < weeks_in_month) {
/* Increase the week count */
selfCalender.options.extras.currentWeek += 1;
} else {
/* Reset the week count */
selfCalender.options.extras.currentWeek = 0;
/* Go to next month */
selfCalender.next();
}
selfCalender.render();*/
/* Get numbers of weeks in the month */
var weeks_in_month = self.weeksInMonth(selfCalender.month) - 1;
if(selfCalender.options.extras.currentWeek < weeks_in_month) {
/* Increase the week count */
selfCalender.options.extras.currentWeek += 1;
selfCalender.render();
} else if(selfCalender.options.extras.currentWeek > weeks_in_month) {
/* If we started at the last week of the month, we want to skip over currentWeek = 0 */
selfCalender.options.extras.currentWeek = 1;
selfCalender.next();
} else {
/* Reset the week count */
selfCalender.options.extras.currentWeek = 0;
/* Go to next month */
selfCalender.next();
}
});
/* Previous button handler */
$('.book-me-week-calender .clndr-previous-button').on('click', function() {
/* Get numbers of weeks in the month */
/*var weeks_in_month = Math.floor(selfCalender.month.weeks_in_month() / 7) - 1;
if(selfCalender.options.extras.currentWeek > 0) {
/* Decrease the week count */
selfCalender.options.extras.currentWeek -= 1;
} else {
/* Reset the week count */
selfCalender.options.extras.currentWeek = weeks_in_month;
/* Go to previous month */
selfCalender.back();
}
selfCalender.render();*/
if(selfCalender.options.extras.currentWeek > 0) {
/* Decrease the week count */
selfCalender.options.extras.currentWeek -= 1;
selfCalender.render();
}
/* however if we've crossed 0, we need weeks_in_month to reflect LAST month
before clndr has had a chance to go back. */
else {
var weeks_in_month = self.weeksInMonth( moment(selfCalender.month).subtract('month', 1) ) - 1;
/* Reset the week count */
selfCalender.options.extras.currentWeek = weeks_in_month;
/* Go to previous month */
selfCalender.back();
}
});
}
});
For the next month it shows the invalid date and for the previous month it gives "TypeError: selfCalender.month.weeks_in_month is not a function"
from clndr.
I got error when month change when month is change
var
currentDate = _.isNull(currentDate) ? moment.tz(this.selected_timezone).startOf('day') : currentDate;
self.calenderScript = $chooseDate.clndr({
// template: $('script#bookMeClndrTemplate').html(),
template: $('script#clndr_template').html(),
constraints: {
startDate: currentDate.format('YYYY-MM-DD')
},
ignoreInactiveDaysInSelection: true,
trackSelectedDate: true,
showAdjacentMonths: true,
ready: function () {
},
clickEvents: {
click: function (target) {
}
},
onMonthChange(momentObj) {
}
},
extras: {
availableSlots: [],
currentWeek: Math.floor( ( ( (moment().date() + moment().startOf('month').weekday() ) - 1 ) / ( self.weeksInMonth(moment() ) * 7) ) * self.weeksInMonth( moment() ) )
},
doneRendering: function() {
var selfCalender=this;
/* Next button handler */
$('.book-me-week-calender .clndr-next-button').on('click', function() {
/* Get numbers of weeks in the month */
var weeks_in_month = Math.floor(self.calenderScript.month.daysInMonth() / 7) + 1;
if(self.calenderScript.options.extras.currentWeek < weeks_in_month) {
/* Increase the week count */
self.calenderScript.options.extras.currentWeek += 1;
} else {
/* Reset the week count */
self.calenderScript.options.extras.currentWeek = 0;
/* Go to next month */
self.calenderScript.next();
}
self.calenderScript.render();
self.showTimeSlot = false;
console.log("next",self.calenderScript.month.daysInMonth());
console.log("next",self.calenderScript.options);
});
/* Previous button handler */
$('.book-me-week-calender .clndr-previous-button').on('click', function() {
/* Get numbers of weeks in the month */
var weeks_in_month = Math.floor(self.calenderScript.month.daysInMonth() / 7) + 1;
if(self.calenderScript.options.extras.currentWeek > 0) {
/* Decrease the week count */
self.calenderScript.options.extras.currentWeek -= 1;
} else {
/* Reset the week count */
self.calenderScript.options.extras.currentWeek = weeks_in_month;
/* Go to previous month */
self.calenderScript.back();
}
self.calenderScript.render();
});
}
});
Please help me.I need to fix this by today.
from clndr.
Hi @kylestetz , thanks for providing the week view, is there any way out, where we could provide the "day" view?
from clndr.
Related Issues (20)
- It's possible to move self.options.clickEvents.click.apply(self, [target]); after setting the selected date? HOT 2
- Previous and Next months appear. I just want to show the current month. HOT 5
- how can i translate month into chinese?
- Have multiple classes for an events such as a class for a bank holiday and school holiday class HOT 2
- Feature Request: Multi-day select HOT 1
- set month and year same time HOT 2
- "Na" being displayed instead of previous month's dates HOT 3
- Destroy Clndr In Internet Explorer IE 11 HOT 1
- Generating `daysOfTheWeek` array with only first character HOT 11
- Styling/CSS Not showing HOT 3
- Can I have the mini-calendar without the full calendar?
- Get clicked date in calander
- Drop jQuery dependency HOT 1
- How can I show current month in number?
- how can I stay the same month when returning back to this page HOT 1
- Usage docs should explain how to use eventsThisInterval HOT 1
- hi If I wants to change the calendar start day order from Sunday to Monday how can I change it HOT 2
- Improper translations with the localization features
- Initialization intervalEnd error with more than one month
- CLNDR2 released
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from clndr.