Overview
This tutorial shows how to create a queue of tasks scheduled for a specific day, without setting the time of day and the assigned resource (person, location, etc.).
Users can assign the time of day and resource by dragging the task from the queue to the main Scheduler grid.
License
Licensed for testing and evaluation purposes. Please see the license agreement included in the sample project. You can use the source code of the tutorial if you are a licensed user of DayPilot Pro for JavaScript.
Live Demo
How to Display a Special Row for Queued Tasks
We will display a special frozen row at the top of the JavaScript Scheduler component. This row will display a queue of tasks scheduled for a given day (without a precise time slot).
Users will be able to use drag and drop to move the tasks to the grid and assign a specific time and resource.
Below, you can see that the first row row is marked as frozen (frozen: "top"
) and uses a special id (id: "QUEUE"
):
const app = {
loadData() {
const resources = [
{name: "Queue", id: "QUEUE", frozen: "top", marginBottom: 35},
{name: "Resource 1", id: "R1"},
{name: "Resource 2", id: "R2"},
{name: "Resource 3", id: "R3"},
{name: "Resource 4", id: "R4"},
{name: "Resource 5", id: "R5"},
{name: "Resource 6", id: "R6"},
{name: "Resource 7", id: "R7"},
{name: "Resource 8", id: "R8"},
{name: "Resource 9", id: "R9"},
];
dp.update({resources});
}
};
How to Remove Vertical Lines from the Queue Row
To display one big cell for each day in the queue, we will remove the vertical lines that separate the grid cells from the queue row.
This can be done using the following CSS:
<style>
.scheduler_default_grid_top .scheduler_default_matrix_vertical_line {
display: none;
}
</style>
Adjust Time Range Selecting for the Queue
A custom onTimeRangeSelecting handler will adjust the start and end time of a new event created using drag and drop in the queue row.
The task will always fill the whole day:
onTimeRangeSelecting: args => {
if (args.resource === "QUEUE") {
args.start = args.start.getDatePart().addHours(dp.businessBeginsHour);
args.end = args.start.getDatePart().addHours(dp.businessEndsHour);
}
},
Icon for Adding Tasks to Queue
We will use onBeforeCellRender event handler to display an icon for adding a new task to the queue.
onBeforeCellRender: args => {
if (args.cell.resource === "QUEUE" && args.cell.start.getHours() === 13) {
args.cell.areas = [
{
left: 2,
bottom: 7,
height: 20,
right: 2,
style: "cursor: pointer;",
cssClass: "icon-add",
symbol: "daypilot.svg#plus-4",
toolTip: "Add unscheduled task",
onClick: async args => {
const modal = await DayPilot.Modal.prompt("Name", "Task");
if (modal.canceled) {
return;
}
dp.events.add({
start: args.source.start.getDatePart().addHours(dp.businessBeginsHour),
end: args.source.start.getDatePart().addHours(dp.businessEndsHour).addHours(1),
text: modal.result,
id: DayPilot.guid(),
resource: "QUEUE"
});
},
action: "None"
}
];
}
}
Moving Events between the Queue and the Scheduler Grid using Drag and Drop
We need to use custom moving logic to adjust the start and end time of the task when moving it between the queue and the main Scheduler grid:
onEventMoving: args => {
if (args.e.resource() === "QUEUE") {
const coords = dp.getCoords();
args.start = coords.cell.start;
args.end = coords.cell.end;
}
if (args.resource === "QUEUE") {
args.start = args.start.getDatePart().addHours(dp.businessBeginsHour);
args.end = args.start.getDatePart().addHours(dp.businessEndsHour).addHours(1);
}
},
Full Source Code
And here is the full source code of our example that implements a daily queue of unscheduled tasks in the JavaScript Scheduler component:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>JavaScript Scheduler: Daily Task Queue</title>
<style>
.inqueue.scheduler_default_event,
.inqueue .scheduler_default_event_inner {
border-radius: 5px;
overflow: hidden;
}
.inqueue .scheduler_default_event_inner {
left: 4px;
right: 5px;
padding: 5px;
background: #69af5299;
border-color: #69af52;
color: #333333;
}
.inqueue .scheduler_default_event_bar {
left: 2px;
right: 3px;
}
body .scheduler_default_event_inner {
border-radius: 5px;
padding: 5px;
background: #69af5299;
border-color: #69af52;
color: #333333;
}
.scheduler_default_grid_top .scheduler_default_matrix_vertical_line {
display: none;
}
.icon-add {
color: #ccc;
}
.icon-add:hover {
color: #999;
}
</style>
<!-- DayPilot library -->
<script src="js/daypilot/daypilot-all.min.js"></script>
</head>
<body>
<div class="header">
<h1><a href='https://code.daypilot.org/47406/javascript-scheduler-daily-task-queue'>JavaScript Scheduler: Daily Task Queue</a></h1>
<div><a href="https://javascript.daypilot.org/">DayPilot for JavaScript</a> - HTML5 Calendar/Scheduling Components for JavaScript/Angular/React/Vue</div>
</div>
<div class="main">
<div id="dp"></div>
<div class="generated">Generated using <a href="https://builder.daypilot.org/">DayPilot UI Builder</a>.</div>
</div>
<script>
const scheduler = new DayPilot.Scheduler("dp", {
timeHeaders: [{"groupBy":"Month"},{"groupBy":"Day","format":"d"}, {groupBy: "Hour"}],
scale: "Hour",
days: DayPilot.Date.today().daysInMonth(),
startDate: DayPilot.Date.today().firstDayOfMonth(),
timeRangeSelectedHandling: "Enabled",
showNonBusiness: false,
rowMarginTop: 2,
rowMarginBottom: 2,
cellWidth: 50,
eventMarginBottom: 2,
durationBarVisible: false,
onBeforeEventRender: args => {
if (args.data.resource === "QUEUE") {
args.data.cssClass = "inqueue";
}
},
onTimeRangeSelecting: args => {
if (args.resource === "QUEUE") {
args.start = args.start.getDatePart().addHours(scheduler.businessBeginsHour);
args.end = args.start.getDatePart().addHours(scheduler.businessEndsHour);
}
},
onBeforeCellRender: args => {
if (args.cell.resource === "QUEUE" && args.cell.start.getHours() === 13) {
args.cell.areas = [
{
left: 2,
bottom: 7,
height: 20,
right: 2,
style: "cursor: pointer;",
cssClass: "icon-add",
symbol: "daypilot.svg#plus-4",
toolTip: "Add unscheduled task",
onClick: async args => {
const modal = await DayPilot.Modal.prompt("Name", "Task");
if (modal.canceled) {
return;
}
scheduler.events.add({
start: args.source.start.getDatePart().addHours(scheduler.businessBeginsHour),
end: args.source.start.getDatePart().addHours(scheduler.businessEndsHour).addHours(1),
text: modal.result,
id: DayPilot.guid(),
resource: "QUEUE"
});
},
action: "None"
}
];
}
},
onEventMoving: args => {
if (args.e.resource() === "QUEUE") {
const coords = scheduler.getCoords();
args.start = coords.cell.start;
args.end = coords.cell.end;
}
if (args.resource === "QUEUE") {
args.start = args.start.getDatePart().addHours(scheduler.businessBeginsHour);
args.end = args.start.getDatePart().addHours(scheduler.businessEndsHour).addHours(1);
}
},
onTimeRangeSelected: async (args) => {
const dp = args.control;
const modal = await DayPilot.Modal.prompt("Create a new event:", "Task");
dp.clearSelection();
if (modal.canceled) { return; }
dp.events.add({
start: args.start,
end: args.end,
id: DayPilot.guid(),
resource: args.resource,
text: modal.result
});
},
treeEnabled: true,
});
scheduler.init();
const app = {
init() {
this.loadData();
},
loadData() {
const resources = [
{name: "Queue", id: "QUEUE", frozen: "top", marginBottom: 35},
{name: "Resource 1", id: "R1"},
{name: "Resource 2", id: "R2"},
{name: "Resource 3", id: "R3"},
{name: "Resource 4", id: "R4"},
{name: "Resource 5", id: "R5"},
{name: "Resource 6", id: "R6"},
{name: "Resource 7", id: "R7"},
{name: "Resource 8", id: "R8"},
{name: "Resource 9", id: "R9"},
];
scheduler.update({resources});
}
};
app.init();
</script>
</body>
</html>