The onScrollEnd event handler fires when the user finishes scrolling the JavaScript Scheduler grid.
DayPilot.Scheduler.onScrollEnd(args)args.control (DayPilot.Scheduler) - control instance (available since 2026.1.6836)
args.viewport.start (DayPilot.Date) - read-only viewport start date/time
args.viewport.end (DayPilot.Date) - read-only viewport end date/time
args.viewport.resources (array of string | number) - read-only list of resource IDs currently visible in the viewport
Additional properties available when DayPilot.Scheduler.dynamicLoading is enabled:
args.async (boolean) - if set to true, the Scheduler waits for args.loaded() before updating; the default value is true
args.events (array) - event data objects to load; each item uses the DayPilot.Event.data structure
args.remove (array of string | number) - events to remove; experimental, use args.clearEvents = true instead
args.clearEvents (boolean) - whether to clear existing events before loading the new args.events data; the default value is true
args.loaded() - performs the asynchronous update
Available since version 2023.3.5731.
Since version 2026.1.6836, this event always fires after scrolling. In earlier versions, it was only fired when dynamic event loading was enabled.
This event is based on the native scrollend event and may not be supported in all browsers, including Safari.
When using dynamic event loading, the only supported actions inside onScrollEnd are setting args properties and calling args.loaded(). Do not change Scheduler properties or call refresh methods such as update(), rows.filter(), or rows.load().
Angular: Do not set the [events] attribute when dynamic event loading is enabled. In combination with args.clearEvents = false, it can cause an infinite loop.
React: Do not set the events prop when dynamic event loading is enabled, and do not save the events loaded in onScrollEnd back to the wrapper events prop. This can cause an infinite loop.
JavaScript
const dp = new DayPilot.Scheduler("dp", {
dynamicLoading: true,
onScrollEnd: async (args) => {
args.async = true;
const start = args.viewport.start;
const end = args.viewport.end;
const resources = args.viewport.resources.join(",");
const {data} = await DayPilot.Http.get(`/api/events?start=${start}&end=${end}&resources=${resources}`);
args.events = data;
args.loaded();
},
// ...
});
dp.init();Angular
<daypilot-scheduler [config]="config"></daypilot-scheduler>config: DayPilot.SchedulerConfig = {
dynamicLoading: true,
onScrollEnd: async (args) => {
args.async = true;
const start = args.viewport.start;
const end = args.viewport.end;
const resources = args.viewport.resources.join(",");
const {data} = await DayPilot.Http.get(`/api/events?start=${start}&end=${end}&resources=${resources}`);
args.events = data;
args.loaded();
},
// ...
};React
<DayPilotScheduler
dynamicLoading={true}
onScrollEnd={onScrollEnd}
{/* ... */}
/>const onScrollEnd = async (args) => {
args.async = true;
const start = args.viewport.start;
const end = args.viewport.end;
const resources = args.viewport.resources.join(",");
const {data} = await DayPilot.Http.get(`/api/events?start=${start}&end=${end}&resources=${resources}`);
args.events = data;
args.loaded();
};Vue
<DayPilotScheduler
:dynamicLoading="true"
@scrollEnd="onScrollEnd"
<!-- ... -->
/>const onScrollEnd = async (args) => {
args.async = true;
const start = args.viewport.start;
const end = args.viewport.end;
const resources = args.viewport.resources.join(",");
const {data} = await DayPilot.Http.get(`/api/events?start=${start}&end=${end}&resources=${resources}`);
args.events = data;
args.loaded();
};Dynamic Event Loading [doc.daypilot.org]