I have a list of objects with start and end times:
let times = [
{start: moment().add(1, 'days'), end: moment().add(2, 'days')},
{start: moment().add(1, 'days'), end: moment().add(2, 'days')},
{start: moment().add(4, 'days'), end: moment().add(5, 'days')},
{start: moment().add(1, 'days'), end: moment().add(7, 'days')},
{start: moment().add(2, 'days'), end: moment().add(3, 'days')},
]
I'd like to sort these times by start time (earliest to latest) while breaking ties with end time (shorter end time comes first).
So the results would look like this:
let sortedTimes = [
{start: moment().add(1, 'days'), end: moment().add(2, 'days')},
{start: moment().add(1, 'days'), end: moment().add(2, 'days')},
{start: moment().add(1, 'days'), end: moment().add(7, 'days')},
{start: moment().add(2, 'days'), end: moment().add(3, 'days')},
{start: moment().add(4, 'days'), end: moment().add(5, 'days')},
]
Is there a preferred Javascript way to do this with higher order functions/ minimal syntax? I began writing a script but the logic contains a lot of if - else if - else syntax, was wondering if there was a better way. Thanks again!
From the looks of it, I'm assuming you're using moment.js. This doesn't utilize a higher order function, but just uses the Array.prototype.sort method with a custom comparator function and the syntax is pretty terse:
times.sort(function(a, b) {
return a.start.isBefore(b.start) ? -1 : a.start.isSame(b.start) ? a.end.isBefore(b.end) ? -1 : 1 : 1;
});
Written out:
times.sort(function(a, b) {
if (a.start.isBefore(b.start)) {
return -1; // a before b
} else if (a.start.isSame(b.start)) {
// break tie on end
if (a.end.isBefore(b.end)) {
return -1; // a before b
} else {
return 1; // b before a
}
} else {
return 1; // b before a
}
}
Here's a plunkr if you want to see it in action.
Perhaps lodash sortBy:
_.sortBy(times, ['start', 'end']);
See:
https://github.com/lodash/lodash/blob/master/dist/lodash.core.js#L2130-L2139
Related
I am using ngx-daterangepicker-material for date picker in angular 9 project. I have requirement that, when user selects start date than 60 days from start date to the future and past should be not be selectable
For example, if user select start date 1st Jan 2021 than end date between 1st of March 2021(60 days future) and 1st of November 2020(60 days past) should not be selectable for user. rest all end date should be selectable
Tried doing it with minDate, maxDate but wasn't able to do it.
Thanks in advance!
input
type="text"
ngxDaterangepickerMd
[(ngModel)]="selected"
(rangeClicked)="rangeClicked($event)"
(datesUpdated)="datesUpdated($event)"
[showCustomRangeLabel]="true"
[alwaysShowCalendars]="true"
[ranges]="ranges"
[linkedCalendars]="true"
[showClearButton]="false"
[isInvalidDate] = "isInvalidDate"
[keepCalendarOpeningWithRange]="keepCalendarOpeningWithRange"
[showRangeLabelOnInput]="showRangeLabelOnInput"
/>
constructor() {
this.maxDate = moment().add(2, 'weeks');
this.minDate = moment().subtract(3, 'days');
this.alwaysShowCalendars = true;
this.keepCalendarOpeningWithRange = true;
this.showRangeLabelOnInput = true;
this.selected = {
startDate: moment().subtract(1, 'days'),
endDate: moment().subtract(1, 'days'),
};
}
rangeClicked(range) {
console.log('[rangeClicked] range is : ', range);
}
datesUpdated(range) {
console.log('[datesUpdated] range is : ', range);
}
export class DateRangeComponent implements OnInit {
selected: any;
alwaysShowCalendars: boolean;
showRangeLabelOnInput: boolean;
keepCalendarOpeningWithRange: boolean;
maxDate: moment.Moment;
minDate: moment.Moment;
ranges: any = {
Today: [moment(), moment()],
Yesterday: [moment().subtract(1, 'days'), moment().subtract(1, 'days')],
'Last 7 Days': [moment().subtract(6, 'days'), moment()],
'Last 30 Days': [moment().subtract(29, 'days'), moment()],
'This Month': [moment().startOf('month'), moment().endOf('month')],
'Last Month': [
moment()
.subtract(1, 'month')
.startOf('month'),
moment()
.subtract(1, 'month')
.endOf('month'),
],
};
isInvalidDate = (m: moment.Moment) => {
return this.invalidDates.some(d => d.isSame(m, 'day'));
};
constructor() {
this.maxDate = moment().add(2, 'weeks');
this.minDate = moment().subtract(3, 'days');
this.alwaysShowCalendars = true;
this.keepCalendarOpeningWithRange = true;
this.showRangeLabelOnInput = true;
this.selected = {
startDate: moment().subtract(1, 'days'),
endDate: moment().subtract(1, 'days'),
};
}
rangeClicked(range) {
console.log('[rangeClicked] range is : ', range);
}
datesUpdated(range) {
console.log('[datesUpdated] range is : ', range);
}
}
My goal is to show all the days of a selected year. From January to December, so that the user can pick or view the dates on that year. For that, I'm using ion2-calendar.
So far I have this:
date: Date = new Date();
async openCalendar() {
const options: CalendarModalOptions = {
title: 'Plano de FĂ©rias',
//defaultDate: new Date(2019,0,1),
pickMode: 'multi',
color: 'primary',
weekdays : ['D', 'S', 'T', 'Q', 'Q', 'S', 'S'],
weekStart : 1,
canBackwardsSelected: false,
closeLabel : 'Fechar',
doneLabel : 'OK',
disableWeeks : [0,6],
from : new Date(2019,0,1),
to : new Date(2019,11,31)
};
const myCalendar = await this.modalCtrl.create({
component: CalendarModal,
componentProps: { options },
});
myCalendar.present();
const event: any = await myCalendar.onDidDismiss();
const { data: date, role } = event;
if (role === 'done') {
this.date = date.dateObj;
}
console.log(date);
console.log('role', role);}
With this code, which the from:new Date(2019,0,1), to:new Date(2019,11,31) means that the start date is the first of january and the last is the 31st of December of 2019, the month December doesn't show, either do the January of 2020, but Feb. and so on do.
If I change the code to from:new Date(2019,1,1), to:new Date(2019,11,31), The Output is what I want, but there's no January month.
I don't know if it is a bug, or if I'm doing something wrong, but so far I did not find an appropriate answer. If you know some plugin for ionic4, that looks like this, share it. Thank you for your time in advance.
SOLVED
Solution can be found in here.
I'm using FullCalendar.js to show tasks entered by users. For this I have created a pop up to take Event basic details and details about recurrence. An event can recur daily, weekly, 28 day, 31 day , 30 day cycles. I have been able to render events for daily and weekly cases but I cant think about how to render events occurrences with 28/30/31 days between them.
My code for calendar is as follows:
$('#calendar').fullCalendar({
//height: 420,
header: {
left: 'prev,next today',
center: 'title',
right: 'month,agendaWeek,agendaDay'
},
defaultDate: moment(),
defaultView: 'month',
eventRender: function (event, element, view) {
console.log(event.start.format());
if (event.ranges == undefined)
return true;
else {
return (event.ranges.filter(function (range) {
if (range.end == undefined)//Check if only start is given
return (event.end.isAfter(range.start))
else
return (event.start.isBefore(range.end) &&//If both start and end date is given
event.end.isAfter(range.start));
}).length) > 0;
}
},
events: function (start, end, timezone, callback) {
var events = getEvents(start, end); //This should be a JSON request
callback(events);
},
eventClick: function (calEvent, jsEvent, view) {
alert('Event: ' + calEvent.title);
//$('#btnOpenPopUp').click();
}
});
and json for events is like so:
{
title: "My repeating event",
id: 1,
start: '10:00', // a start time (10am in this example)
end: '14:00', // an end time (6pm in this example)
dow: [1, 2, 3, 4, 5], // Repeat monday and thursday
ranges: [{
start: moment().startOf('month').subtract(1, 'month'),
end: moment().startOf('month').subtract(1, 'month').add(7, 'd'),
}, {
start: moment('2016-12-15', 'YYYY-MM-DD'), //all of february
//end: moment('2016-11-01', 'YYYY-MM-DD').endOf('month'),
}
I need help to render tasks that occur after every 28 days. Any suggestions?
Maybe you could use later.js project (http://bunkat.github.io/later/index.html) to calculate the occurrences of the tasks. This code sample will produce the all occurrences between 2 dates for every 28 days:
<html>
<head>
<script src="moment.js" type="text/javascript"></script>
<script src="moment-recur-min.js" type="text/javascript"></script>
<script type="text/javascript">
var recurrence = moment().recur("2016-12-06", "2017-12-06").every(28).days();
var allDates = recurrence.all("L");
console.log(allDates);
</script>
</head>
<body>
test
</body>
</html>
I have a drop down list(screenshot attached),when we select any one like this year so how can we send StartIndex and EndIndex in backend using date Object using javascript,angular js.
Thanks In Advance any help will be appriciated
StatIndex:2016-01-01T00:00:00+5:30
EndIndex :2016-12-31T23:59:59+5:30
code for Index Range
this.indexRanges = ['This Year', 'Last Year', 'This Quarter', 'Last Quarter', 'This Month', 'Last Month', 'This Week',
'Last Week', 'Last 72 Hours', 'Last 48 Hours', 'Last 24 Hours', 'Today', 'Yesterday', 'Last Hours', 'This Hours',
'This 30 Minutes', 'Last 30 Minutes', 'This 15 Minutes', 'Last 15 Minutes', 'This 10 Minutes', 'Last 10 Minutes'];
send in backend using date Object using javascript,angular js
You most likey want the start date:
StatIndex:2016-01-01T00:00:00+5:30
This can be converted to a Date object quite easily using the Date constructor. For example:
var StatIndex = '2016-01-01T00:00:00+5:30';
const date = Date(StatIndex);
const toSend = {date:date};
const json = JSON.stringify(toSend);
As #Hassan Tariq mentioned in the comments, you need to write your own methods for it. To help you with there is a good library to play with dates moment.js
I am getting data from a DB for populating events in fullcalendar.js
I get this information prior to initiating $('#calendar').fullCalendar({})
If I knew how many events I was going to have I could create the calendar with the code below
events: [
eventz[0],
eventz[1]
]
Where eventz contain information like
eventz[eventcounter]={
className: title[counter],
title: title[counter],
start: new Date(y, m, weekday, result[hour1], result[minute1]),
end: new Date(y, m, weekday, result[hour2], result[minute2]),
allDay: false
};
EDIT: More information-events would normally contain information written like below
events:[
{//event1
title: 'TENTATIVE',
start: new Date(y, m, monday, 0, 30),
end: new Date(y, m, monday, 1, 0),
allDay: false
},
{//event2
title: 'TENTATIVE',
start: new Date(y, m, monday, 0, 30),
end: new Date(y, m, monday, 1, 0),
allDay: false
}
]
Unfortunately, I don't know how many events I'm going to get.
I thought that prior to initiating the calendar, I could combine the events into one object or variable (something like the code below-where allevents={eventz[0]},{eventz[1]}).
events: [
allevents
]
QUESTIONs
Is it possible to combine events into one object or variable like above? If yes, how? If no, I'd be interested in alternative methods for entering dynamic event data into fullcalendar. Thanks :)
WHAT I have tried
//combine all events into one
for (var i=0;i<=counter;i++)
{
allevents+=eventz[i];
if (i!=counter)
{
allevents+=',';
}
}
I've tried quite a few things, but this feels like I'm doing ridiculous stuff and this seems like an easy question (for people other than me).
I think this is what you are looking for.
Instead of using 'events' attribute use 'eventSources' attribute.
Before:
events : eventArrayFirst
After:
eventSources: [
eventArrayFirst,
eventArraySecond
]
I used array concatenation to solve my problem.
//Combines all events into one
if (eventcounter>0) //Check that there is an event!
{
var allevents=[eventz[0]];
for (var varname=1; varname<=eventcounter; varname++)
{
allevents=allevents.concat([eventz[varname]]);
}
}
If your final array after combining all the events in single array looks like
var eventz = [
{//event1
title: 'TENTATIVE',
start: new Date(y, m, monday, 0, 30),
end: new Date(y, m, monday, 1, 0),
allDay: false
},
{//event2
title: 'TENTATIVE',
start: new Date(y, m, monday, 0, 30),
end: new Date(y, m, monday, 1, 0),
allDay: false
}
];
Then this example may help you