I'm developing calendar app with Javascript and Django . I don't now how to display item by date by clicking the day . Is there any solutions ? I have a guess that I need to get elements by ajax on clicking the date . Here is some code :
models.py
class Item(models.Model):
title=models.CharField(max_length=200)
date = models.DateTimeField(default=datetime.now,blank=True)
is_published=models.BooleanField(default=True)
views.py
def calendar(request):
item = Item.objects.order_by('-date').filter(is_published=True)
context={
'item':item,
}
return render(request,'main/calendar.html',context)
Javascript calendar draw methods
drawAll() {
this.drawWeekDays();
this.drawMonths();
this.drawDays();
this.drawYearAndCurrentDay();
this.drawEvents();
}
drawYearAndCurrentDay() {
let calendar = this.getCalendar();
this.elements.year.innerHTML = calendar.active.year;
this.elements.currentDay.innerHTML = calendar.active.day;
this.elements.currentWeekDay.innerHTML = AVAILABLE_WEEK_DAYS[calendar.active.week];
}
drawDays() {
let calendar = this.getCalendar();
let latestDaysInPrevMonth = this.range(calendar.active.startWeek).map((day, idx) => {
return {
dayNumber: this.countOfDaysInMonth(calendar.pMonth) - idx,
month: new Date(calendar.pMonth).getMonth(),
year: new Date(calendar.pMonth).getFullYear(),
currentMonth: false
}
}).reverse();
let daysInActiveMonth = this.range(calendar.active.days).map((day, idx) => {
let dayNumber = idx + 1;
let today = new Date();
return {
dayNumber,
today: today.getDate() === dayNumber && today.getFullYear() === calendar.active.year && today.getMonth() === calendar.active.month,
month: calendar.active.month,
year: calendar.active.year,
selected: calendar.active.day === dayNumber,
currentMonth: true
}
});
Here is constructor of class Calendar
constructor(options) {
this.options = options;
this.elements = {
days: this.getFirstElementInsideIdByClassName('calendar-days'),
week: this.getFirstElementInsideIdByClassName('calendar-week'),
month: this.getFirstElementInsideIdByClassName('calendar-month'),
year: this.getFirstElementInsideIdByClassName('calendar-current-year'),
currentDay: this.getFirstElementInsideIdByClassName('display_day'),
currentWeekDay: this.getFirstElementInsideIdByClassName('calendar-left-side-day-of-week'),
prevYear: this.getFirstElementInsideIdByClassName('calendar-change-year-slider-prev'),
nextYear: this.getFirstElementInsideIdByClassName('calendar-change-year-slider-next')
};
this.date = +new Date();
this.options.maxDays = 37;
this.init();
}
getFirstElementInsideIdByClassName(className) {
return document.getElementById(this.options.id).getElementsByClassName(className)[0];
}
Here is template
<div class="right-side">
<div class="text-right calendar-change-year">
<div class="calendar-change-year-slider">
<span class="fa fa-caret-left cursor-pointer calendar-change-year-slider-prev"></span>
<span class="calendar-current-year"></span>
<span class="fa fa-caret-right cursor-pointer calendar-change-year-slider-next"></span>
</div>
</div>
<div class="calendar-month-list">
<ul class="calendar-month"></ul>
</div>
<div class="calendar-week-list">
<ul class="calendar-week"></ul>
</div>
<div class="calendar-day-list">
<ul class="calendar-days"></ul>
</div>
</div>
<h1 class="calendar__heading calendar__heading-2 display_day"></h1>
<h1 class="calendar__heading calendar-left-side-day-of-week"></h1>
Here is what I want
Or is there a way to change calendar ? This calendar isn't so necessary
The javascript code should detect which day you clicked, then it should call an endpoint that will end up in your django view. The view should receive the day and filter the items by date, something like this:
Entry.objects.filter(date=selected_day)
This should return all the items for a given day.
Related
Hi, i maked a calendar than have some day class than they added in componentDidMount() method and after that i can not add event to the day classes.
In fact when i get the day class length, or i want to select this class, return me none object.
I add the target elements in componentdidMount() method.
i add the eventListener in the componentdidMount() method.
The element adder and eventListener both are in componentDidMount()
The codes:
the day adder and event listener
for (let day = 1; day <= days.length; day++){
const weekend = isWeekend(year, month, day);
const today = isToday(year, month, day);
let name = '';
if(day <= 7){
const dayName = getDayName(year, month,day);
name = `<div className="name">${dayName}</div>`
}
calendar.insertAdjacentHTML(
"beforeend",
`<div className='day${weekend ? " weekend" : ""}${today ? " today" : ""}' data-year="${year}" data-month="${month}" data-day="${day}" onClick={this.dayClick}>
${name}
${day}
${weekend ? "<br/><p style='color:#FFA500'>weekend</p>" : ""}
${today ? "<h3 style='color:#9af467'>today</h3>" : ""}
</div>`
);
}
document.querySelectorAll('#app-calendar .day').forEach(day => {
day.addEventListener("click", event => {
event.currentTarget.classList.toggle("selected");
});
day.addEventListener("dblclick", event => {
let element = event.target;
let year = element.getAttribute('data-year');
let month = element.getAttribute('data-month');
let day = element.getAttribute('data-day');
let date = Date(year + '-' + month + '-' + day);
this.setState({
date: formatDate(date)
});
console.log(this.state.date);
});
});
The render code(Html)
render(){
return(
<div className="root">
<div className="clalendar-header">
<div id="previous" className="shift"><h3>previous</h3></div>
<div id="month-name" className="month-name"></div>
<div id="future" className="shift"><h3>future</h3></div>
</div>
<div className="content">
<div id="app-calendar"></div>
</div>
</div>
);
}
I am trying to group a list of messages in monthly sections. Every time the month changes I want to add a header <h2>Previous Month</h2> and then display all the messages from that month.
Here is my attempt:
MessageList.js
import React from "react"
export default class MessageList extends React.Component {
constructor() {
super()
}
render() {
var currentDate = new Date()
var currentMonth = currentDate.getMonth()
var timeline=""
var mssgTypeList = {
"this_month" : [],
"last_month" : [],
"previous_month" : []
}
this.props.messages.forEach(function(message,index){
var date = message.date.substring(0, 10)
var time = message.date.slice(12)
var messageDate = new Date(date)
var messageMonth = messageDate.getMonth()
if(currentMonth == messageMonth) {
timeline == 'this_month'
} else if(currentMonth == messageMonth + 1){
timeline = 'last_month'
} else if(currentMonth == messageMonth + 2) {
timeline = 'previous_month'
}
mssgTypeList[timeline].push(message);
});
const ThisMonthMessageList = mssgTypeList["this_month"].map((message) => {
var date = message.date.substring(0, 10);
var time = message.date.slice(12);
return (
<li className="list-group-item" key={message.id}>
Date: {date} <br></br>
Time: {time} <br></br>
Body: {message.body}
</li>
)
});
const LastMonthMessageList = mssgTypeList["last_month"].map((message) => {
var date = message.date.substring(0, 10);
var time = message.date.slice(12);
return (
<li className="list-group-item" key={message.id}>
Date: {date} <br></br>
Time: {time} <br></br>
Body: {message.body}
</li>
)
})
const PreviousMonthMessageList = mssgTypeList["previous_month"].map((message) => {
var date = message.date.substring(0, 10);
var time = message.date.slice(12);
return (
<li className="list-group-item" key={message.id}>
Date: {date} <br></br>
Time: {time} <br></br>
Body: {message.body}
</li>
)
})
return (
<div id="messageList">
<h2>This Month</h2>
<ul className="list-group this-month-group">
{ThisMonthMessageList}
</ul>
<h2>Last Month</h2>
<ul className="list-group last-month-group">
{LastMonthMessageList}
</ul>
<h2>Previous Month</h2>
<ul className="list-group previous-month-group">
{PreviousMonthMessageList}
</ul>
</div>
)
}
The problem here is that this only generates a limited number of monthly sections; Basically sections that I hardcoded in mssgTypeList. It does not dynamically create a new section whenever the month changes.
How do I dynamically generate a new section every time the month changes?
Or is there an alternative way to sort messages in monthly sections? Maybe create additional components?
Its probably a better idea to put all the logic that depends in the props in the componentWillReceiveProps Method and the same should be present in the componentDidMount function since componentWillReceiveProps is not being called the initial time. Also having all this logic in the render is expensive since render is called any state change.
Dynamic rendering can be achieved in the following manner, however it would be better if you include the month with the year as a key.
export default class MessageList extends React.Component {
constructor() {
super();
this.state = {
msgTypeList : {
}
}
}
componentDidMount() {
var currentDate = new Date()
var currentMonth = currentDate.getMonth()
var messageTypeList = {}
this.props.messages.forEach((message, index) => {
var date = message.date.substring(0, 10)
var messageDate = new Date(date)
var messageMonth = messageDate.getMonth();
messageTypeList[messageMonth].push(message);
})
this.setState({messageTypeList});
}
componentWillReceiveProps(nextProps) {
var currentDate = new Date()
var currentMonth = currentDate.getMonth()
var timeline=""
var messageTypeList = {}
nextProps.messages.forEach((message, index) => {
var date = message.date.substring(0, 10)
var messageDate = new Date(date)
var messageMonth = messageDate.getMonth();
messageTypeList[messageMonth].push(message);
})
this.setState({messageTypeList});
}
render() {
return (
<div id="messageList">
{Object.keys(this.state.messageTypeList).map((key) => {
return (
<div>
<h2>{key}</h2>
<ul className="list-group">
{this.state.messageTypeList[key].map((message) => {
var date = message.date.substring(0, 10);
var time = message.date.slice(12);
return (
<li className="list-group-item" key={message.id}>
Date: {date} <br></br>
Time: {time} <br></br>
Body: {message.body}
</li>
)
})}
</ul>
</div>
)
})
}
</div>
)
}
You are on the right track. Notice that {ThisMonthMessageList} is not hard-code but you build it. Well you can do the same thing for your entire message list. Your render return statement would then look something like this:
return (
<div id="messageList">
{messageList}
</div>
);
Hopefully that's enough to get you thinking about this the right way.
I just want to scroll downside and after that come back to the beginning of the list.
Now I can't use my grid.
I know that there are thousands of examples of how to do ui-scroll,
but there are no any example with Angular 1.5 components
Please help.
index.html
//add ui-scroll-viewport
<md-content flex layout-padding class="viewport" id="viewport-serviceDatasource" ui-scroll-viewport>
// added ui-scroll, this part is responsible for loading by week
<div layout="raw" layout-xs="column" class="week" layout-sm="column" layout-align="space-between start" flex="none"
ui-scroll="week in $ctrl.grid">
<!-- outlines days -->
<div flex="none" layout="column" layout-fill ng-repeat="day in week">
<!-- current day header-->
<div layout="row" layout-align="space-between center" flex-gt-sm="none" flex="none" style="height: 30px">
<div flex="none" class="md-body-1" style="min-width: 24px">{{::day.title}}</div>
</div>
</div>
</div>
</md-content>
app.js
class CalendarCtrl {
constructor($log, $q, $timeout, $scope) {
'ngInject';
this._$log = $log;
this._$q = $q;
this._$timeout = $timeout;
this._$scope = $scope;
this.grid = {};
// Tried to use $Scope
this._$scope.grid = {};
}
$onInit() {
// Get the first day of the week curry
let currDay = moment().weekday(0),
startDay = moment(currDay).add(-5,'w'),
endDay = moment(currDay).add(5,'w');
// Error here. I think so
this.getCalendarGrid(startDay, endDay).then(
(success) => {
// Get all our days, in the form of a grid
var result = success;
var grid = {};
grid.get = (index, count, success) =>{
index = index <= 0 ? index + 1 : index -1;
success(result.slice(index, index + count));
};
this.grid = grid;
this._$log.debug('Calendar: getCalendarGrid', this.grid);
},
(error) => this._$log.debug('Calendar: onInit, getCalendar error', error),
(week) => this._$log.debug('Calendar: onInit, getCalendar notify', week)
);
}
/**
*
* #returns {Promisse}
*/
getCalendarGrid(startDay, endDay){
let start = startDay, end = endDay;
let result = this._$q.defer(),
grid = {},
index = 0,
diff = end.diff(start,'d'),
day = {
title: null,
activity: []
},
week = {};
while (diff != 0){
// go through all the days.
day.title = start.format('DD');
angular.extend(week, {[start.format('YYYYMMDD')]: day});
day = {
title: null,
activity: []
};
// put by week
if ((diff % 7 == 1) || diff == 0){
week = { [start.format('YYYYWW')]: week };
angular.extend(grid,week);
result.notify(week);
week = {};
}
start.add(1,'d');
diff = end.diff(start,'d');
}
result.resolve(grid);
return result.promise;
}
}
Console screen
Console screen with errors
I am using Express and AngularJS. I tried to add a date picker with ui-bootstrap module. When I add uib-datepicker, it works fine. But when I tried to add a uib-datepicker-popup the result was like that
uib-datepicker-popup
When I click the calendar button, it shows a pop-up but there are only today, clear and close buttons. It do not show the calendar.
Here is my html
<div ng-controller="DatepickerPopupDemoCtrl">
<pre>Selected date is: <em>{{dt | date:'fullDate' }}</em></pre>
<div class="col-md-6">
<p class="input-group">
<input type="text" uib-datepicker-popup class="form-control" ng-model="dt" is-open="popup2.opened" datepicker-options="dateOptions" ng-required="true" close-text="Close" />
<span class="input-group-btn">
<button type="button" class="btn btn-default" ng-click="open2()"><i class="glyphicon glyphicon-calendar"></i></button>
</span>
</p>
</div>
</div>
And the controller
app.controller('DatepickerPopupDemoCtrl', function ($scope) {
$scope.today = function() {
$scope.dt = new Date();
};
$scope.today();
$scope.clear = function() {
$scope.dt = null;
};
$scope.toggleMin = function() {
$scope.inlineOptions.minDate = $scope.inlineOptions.minDate ? null : new Date();
$scope.dateOptions.minDate = $scope.inlineOptions.minDate;
};
$scope.inlineOptions = {
customClass: getDayClass,
minDate: new Date(),
showWeeks: true
};
$scope.dateOptions = {
dateDisabled: disabled,
formatYear: 'yy',
maxDate: new Date(2020, 5, 22),
minDate: new Date(),
startingDay: 1
};
// Disable weekend selection
function disabled(data) {
var date = data.date,
mode = data.mode;
return mode === 'day' && (date.getDay() === 0 || date.getDay() === 6);
}
$scope.toggleMin();
$scope.open2 = function() {
$scope.popup2.opened = !$scope.popup2.opened;
};
$scope.setDate = function(year, month, day) {
$scope.dt = new Date(year, month, day);
};
$scope.format = 'yyyy-MM-dd';
$scope.altInputFormats = ['M!/d!/yyyy'];
$scope.popup2 = {
opened: false
};
var tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate() + 1);
var afterTomorrow = new Date();
afterTomorrow.setDate(tomorrow.getDate() + 1);
$scope.events = [
{
date: tomorrow,
status: 'full'
},
{
date: afterTomorrow,
status: 'partially'
}
];
function getDayClass(data) {
var date = data.date,
mode = data.mode;
if (mode === 'day') {
var dayToCheck = new Date(date).setHours(0,0,0,0);
for (var i = 0; i < $scope.events.length; i++) {
var currentDay = new Date($scope.events[i].date).setHours(0,0,0,0);
if (dayToCheck === currentDay) {
return $scope.events[i].status;
}
}
}
return '';
}
});
Here is the doc that I take the code: https://angular-ui.github.io/bootstrap/
Thanks in advance.
You should use jade with angularjs.
if you want to add date picker popup , you can use the code below
for html
<input type="text" uib-datepicker-popup="" name="dob" placeholder="Please enter date in YYYY-mm-dd format"
ng-model="dob" is-open="popup2.opened" datepicker-options="dateOptions"
ng-required="true" close-text="Close" class="form-control"/>
<span class="input-group-btn">
<button type="button" ng-click="open2()" class="btn btn-default">
<i class="glyphicon glyphicon-calendar"></i>
</button>
</span>
and add this in your controller
$scope.dateOptions = {
formatYear: 'yy',
maxDate: new Date(2020, 5, 22),
minDate: new Date(1970, 1, 1),
startingDay: 1
};
$scope.open = function() {
$scope.popup.opened = true;
};
$scope.popup = {
opened: false
};
function getDayClass(data) {
var date = data.date,
mode = data.mode;
if (mode === 'day') {
var dayToCheck = new Date(date).setHours(0,0,0,0);
for (var i = 0; i < $scope.events.length; i++) {
var currentDay = new Date($scope.events[i].date).setHours(0,0,0,0);
if (dayToCheck === currentDay) {
return $scope.events[i].status;
}
}
}
return '';
}
and this in your css file
<link href="//netdna.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet">
In my case, I was not using npm (or bower) in my project. Hence I had to manually place the following files (downloaded from here ) in the path to make the calendar popup with dates when we use uib-datepicker-popup.
WebPages
L___uib
L___template
L____datepicker
L____datepicker.html
L____day.html
L____month.html
L____year.html
L____datepickerPopup
L____poup.html
Trying to figure out why my Date Object values are not comparing correctly. The same 'GREATER than' string is being appended to both 'review-full-review-comment-wrap' blocks...Is my method of comparing the dateObjects values correct?
<div class="review-full-review-single-wrap">
<div class="review-full-stars">
<span class="review-full-timestamp">
<time itemprop="datePublished" datetime="2014-07-29T11:25:47-07:00">July 29, 2014</time>
</span>
</div>
<div class="review-full-review-comment-wrap"></div>
////*Append LESS THAN*////
</div>
<div class="review-full-review-single-wrap">
<div class="review-full-stars">
<span class="review-full-timestamp">
<time itemprop="datePublished" datetime="2015-05-05T05:50:05-07:00">May 5, 2015</time>
</span>
</div>
<div class="review-full-review-comment-wrap"></div>
////*Append GREATER THAN*////
</div>
function runProgram(){
var elems = document.getElementsByClassName("review-full-timestamp");
for (var i = 0; i < elems.length; i++) {
var timeElems = document.getElementsByTagName("time");
var dateString = Date.parse(timeElems[i].innerHTML);
var dateObj = new Date(dateString);
var startDate = "May 6, 2015";
var startDateObj = new Date(startDate);
}
if(dateObj > startDateObj){
$('.review-full-review-comment-wrap').append('<p>GREATER than</p>');
} else {
$('.review-full-review-comment-wrap').append('<p>LESS than</p>');
}
}
runProgram();
Based on the comment #Bergi made above: Here is the correct function
var startDate = new Date( 'May 6, 2015' );
$( '.review-full-review-single-wrap' ).each( function( i, e ) {
var dateObj = new Date( Date.parse( $( e ).find( '.review-full-timestamp > time' ).attr( 'dateTime' ) ) );
var div = $( e ).find( '.review-full-review-comment-wrap' );
if ( dateObj.getTime() >= startDate.getTime() ) {
div.append( '<p>dateObj is GREATER than startDate</p>' );
} else {
div.append( '<p>dateObj is LESS than startDate</p>' );
}
} );
See getTime()
Consider the following example based on your code:
var dateString = Date.parse('10-23-2015');
var dateObj = new Date(dateString);
var startDate = "May 6, 2015";
var startDateObj = new Date(startDate);
if(dateObj.getTime() > startDateObj.getTime()){
console.log('cool');
}
This outputs
cool
As you can see, 10-23-2015 is bigger than May 6, 2015.
Try adding .getTime() to each date object , push date values to an array , use Array.prototype.some() to determine if either of time elements html parsed to Date objects is greater than startDateObj
function runProgram() {
var times = [];
var startDate = "May 6, 2015";
var startDateObj = new Date(startDate).getTime();
var elems = document.getElementsByClassName("review-full-timestamp");
for (var i = 0; i < elems.length; i++) {
var timeElems = document.getElementsByTagName("time");
var dateString = Date.parse(timeElems[i].innerHTML);
var dateObj = new Date(dateString);
times.push(dateObj.getTime());
}
if (times.some(function(time) {
return time > startDateObj
})) {
$('.review-full-review-comment-wrap').append('<p>GREATER than</p>');
} else {
$('.review-full-review-comment-wrap').append('<p>LESS than</p>');
}
}
runProgram();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="review-full-review-single-wrap">
<div class="review-full-stars">
<span class="review-full-timestamp">
<time itemprop="datePublished" datetime="2014-07-29T11:25:47-07:00">July 29, 2014</time>
</span>
</div>
<div class="review-full-review-comment-wrap"></div>
////*Append LESS THAN*////
</div>
<div class="review-full-review-single-wrap">
<div class="review-full-stars">
<span class="review-full-timestamp">
<time itemprop="datePublished" datetime="2015-05-05T05:50:05-07:00">May 5, 2015</time>
</span>
</div>
<div class="review-full-review-comment-wrap"></div>
////*Append GREATER THAN*////
</div>