Virtual Scrolling in Vue Scheduler
To improve performance when loading a large number of resources and events, the Scheduler supports virtual scrolling. It loads resources and events on demand as you scroll. You can enable virtual loading of a large set of resources and events in the Scheduler by setting the allowVirtualScrolling property to true in the view-specific settings. Virtual loading of events is also available in the Agenda view by setting the same property to true in the agenda view-specific settings.
<template>
<div id='app'>
<div id='container'>
<ejs-schedule id='Schedule' ref='ScheduleObj' width='100%' height='550px' :selectedDate='selectedDate'
:eventSettings='eventSettings' :group='group'>
<e-views>
<e-view option='TimelineMonth' :eventTemplate="'timelineEventTemplate'"
:allowVirtualScrolling='virtualScroll' isSelected="true">
<template v-slot:timelineEventTemplate="{ data }">
<div class='template-wrap' :style='{background: data.PrimaryColor}'>
<div class="subject" :style='{background: data.SecondaryColor}'></div>
</div>
</template>
</e-view>
<e-view option="TimelineYear" orientation="Vertical"
:allowVirtualScrolling="virtualScroll"></e-view>
</e-views>
<e-resources>
<e-resource field='OwnerId' title='Owner' name='Owners' :allowMultiple='allowMultiple'
:dataSource='ownerData' textField='Text' idField='Id' colorField='Color'>
</e-resource>
</e-resources>
</ejs-schedule>
</div>
</div>
</template>
<script setup>
import { provide } from "vue";
import { generateResourceData, generateStaticEvents } from './datasource.js';
import { ScheduleComponent as EjsSchedule, ViewDirective as EView, ViewsDirective as EViews, ResourcesDirective as EResources, ResourceDirective as EResource, TimelineViews, TimelineMonth, TimelineYear, Resize, DragAndDrop } from '@syncfusion/ej2-vue-schedule';
const selectedDate = new Date(2018, 4, 1);
const allowMultiple = true;
const virtualScroll = true;
const group = {
byGroupID: false,
resources: ['Owners']
};
const ownerData = generateResourceData(1, 300, 'Resource');
const eventSettings = { dataSource: generateStaticEvents(new Date(2018, 4, 1), 300, 12) };
provide('schedule', [TimelineViews, TimelineMonth, TimelineYear, Resize, DragAndDrop]);
</script>
<style>
@import "../node_modules/@syncfusion/ej2-base/styles/material3.css";
@import "../node_modules/@syncfusion/ej2-vue-buttons/styles/material3.css";
@import "../node_modules/@syncfusion/ej2-vue-calendars/styles/material3.css";
@import "../node_modules/@syncfusion/ej2-vue-dropdowns/styles/material3.css";
@import "../node_modules/@syncfusion/ej2-vue-inputs/styles/material3.css";
@import "../node_modules/@syncfusion/ej2-vue-navigations/styles/material3.css";
@import "../node_modules/@syncfusion/ej2-vue-popups/styles/material3.css";
@import "../node_modules/@syncfusion/ej2-vue-schedule/styles/material3.css";
.e-schedule .e-timeline-month-view .template-wrap .subject {
padding: 10px 25px;
}
.e-schedule .e-timeline-year-view .template-wrap .subject {
padding: 1px 25px;
}
.e-schedule .e-more-event-popup .template-wrap .subject {
padding: 0px 25px;
}
.e-schedule .template-wrap {
width: 100%;
}
.e-schedule .e-timeline-month-view .e-resource-left-td {
width: 150px;
}
</style><template>
<div id='app'>
<div id='container'>
<ejs-schedule id='Schedule' ref='ScheduleObj' width='100%' height='550px' :selectedDate='selectedDate'
:eventSettings='eventSettings' :group='group'>
<e-views>
<e-view option='TimelineMonth' :eventTemplate="'timelineEventTemplate'"
:allowVirtualScrolling='virtualScroll' isSelected="true">
<template v-slot:timelineEventTemplate="{ data }">
<div class='template-wrap' style='{background: data.PrimaryColor}'>
<div class="subject" style='{background: data.SecondaryColor};'></div>
</div>
</template>
</e-view>
<e-view option="TimelineYear" orientation="Vertical"
:allowVirtualScrolling="virtualScroll"></e-view>
</e-views>
<e-resources>
<e-resource field='OwnerId' title='Owner' name='Owners' :allowMultiple='allowMultiple'
:dataSource='ownerData' textField='Text' idField='Id' colorField='Color'>
</e-resource>
</e-resources>
</ejs-schedule>
</div>
</div>
</template>
<script>
import { generateResourceData, generateStaticEvents } from './datasource.js';
import { ScheduleComponent, ViewDirective, ViewsDirective, ResourcesDirective, ResourceDirective, TimelineViews, TimelineMonth, TimelineYear, Resize, DragAndDrop } from '@syncfusion/ej2-vue-schedule';
export default {
name: "App",
components: {
"ejs-schedule": ScheduleComponent,
"e-views": ViewsDirective,
"e-view": ViewDirective,
"e-resources": ResourcesDirective,
"e-resource": ResourceDirective
},
data: function () {
return {
selectedDate: new Date(2018, 4, 1),
allowMultiple: true,
virtualScroll: true,
group: {
byGroupID: false,
resources: ['Owners']
},
ownerData: generateResourceData(1, 300, 'Resource'),
eventSettings: { dataSource: generateStaticEvents(new Date(2018, 4, 1), 300, 12) }
}
},
provide: {
schedule: [TimelineViews, TimelineMonth, TimelineYear, Resize, DragAndDrop]
}
}
</script>
<style>
@import "../node_modules/@syncfusion/ej2-base/styles/material3.css";
@import "../node_modules/@syncfusion/ej2-vue-buttons/styles/material3.css";
@import "../node_modules/@syncfusion/ej2-vue-calendars/styles/material3.css";
@import "../node_modules/@syncfusion/ej2-vue-dropdowns/styles/material3.css";
@import "../node_modules/@syncfusion/ej2-vue-inputs/styles/material3.css";
@import "../node_modules/@syncfusion/ej2-vue-navigations/styles/material3.css";
@import "../node_modules/@syncfusion/ej2-vue-popups/styles/material3.css";
@import "../node_modules/@syncfusion/ej2-vue-schedule/styles/material3.css";
.e-schedule .e-timeline-month-view .template-wrap .subject {
padding: 10px 25px;
}
.e-schedule .e-timeline-year-view .template-wrap .subject {
padding: 1px 25px;
}
.e-schedule .e-more-event-popup .template-wrap .subject {
padding: 0px 25px;
}
.e-schedule .template-wrap {
width: 100%;
}
.e-schedule .e-timeline-month-view .e-resource-left-td {
width: 150px;
}
</style>For now, the virtual loading of resources and events is not supported in
MonthAgenda,YearandTimelineYear(Horizontal Orientation) views.
Enabling lazy loading for appointments
Lazy loading complements virtual scrolling by fetching appointment data from the server on demand instead of loading all events upfront.
How lazy loading works
When lazy loading is enabled:
- Events are fetched only for the visible resources and current date range.
- As the user scrolls, the Scheduler issues additional server requests.
- Each request includes:
- The resource IDs currently in view
- The active date range
- The server returns only the events relevant to those resources and dates.
This reduces network usage and improves initial load times.
Enabling lazy loading
To enable lazy loading, set the enableLazyLoading property to true in the view configuration.
<template>
<div id='app'>
<div id='container'>
<ejs-schedule ref='ScheduleObj' width='100%' height='550px' :selectedDate='selectedDate' readonly='true'
:eventSettings='eventSettings' :group='group'>
<e-views>
<e-view option='TimelineMonth' :enableLazyLoading='enableLazyLoad' isSelected="true"></e-view>
</e-views>
<e-resources>
<e-resource field='ResourceId' title='Resource' name='Resources' :dataSource='resourceData'
textField='Text' idField='Id' colorField='Color'>
</e-resource>
</e-resources>
</ejs-schedule>
</div>
</div>
</template>
<script setup>
import { provide } from "vue";
import { generateResourceData } from './datasource.js';
import { ScheduleComponent as EjsSchedule, ViewDirective as EView, ViewsDirective as EViews, ResourcesDirective as EResources, ResourceDirective as EResource, TimelineMonth } from '@syncfusion/ej2-vue-schedule';
import { DataManager, WebApiAdaptor } from '@syncfusion/ej2-data';
const dataManager = new DataManager({
url: 'https://services.syncfusion.com/vue/production/api/VirtualEventData',
adaptor: new WebApiAdaptor,
crossDomain: true
});
const selectedDate = new Date(2023, 3, 1);
const enableLazyLoad = true;
const group = {
resources: ['Resources']
};
const resourceData = generateResourceData(1, 1000, 'Resource');
const eventSettings = { dataSource: dataManager };
provide('schedule', [TimelineMonth]);
</script>
<style>
@import "../node_modules/@syncfusion/ej2-base/styles/material3.css";
@import "../node_modules/@syncfusion/ej2-vue-buttons/styles/material3.css";
@import "../node_modules/@syncfusion/ej2-vue-calendars/styles/material3.css";
@import "../node_modules/@syncfusion/ej2-vue-dropdowns/styles/material3.css";
@import "../node_modules/@syncfusion/ej2-vue-inputs/styles/material3.css";
@import "../node_modules/@syncfusion/ej2-vue-navigations/styles/material3.css";
@import "../node_modules/@syncfusion/ej2-vue-popups/styles/material3.css";
@import "../node_modules/@syncfusion/ej2-vue-schedule/styles/material3.css";
</style><template>
<div id='app'>
<div id='container'>
<ejs-schedule ref='ScheduleObj' width='100%' height='550px' :selectedDate='selectedDate' readonly='true'
:eventSettings='eventSettings' :group='group'>
<e-views>
<e-view option='TimelineMonth' :enableLazyLoading='enableLazyLoad' isSelected="true"></e-view>
</e-views>
<e-resources>
<e-resource field='ResourceId' title='Resource' name='Resources' :dataSource='resourceData'
textField='Text' idField='Id' colorField='Color'>
</e-resource>
</e-resources>
</ejs-schedule>
</div>
</div>
</template>
<script>
import { generateResourceData } from './datasource.js';
import { ScheduleComponent, ViewDirective, ViewsDirective, ResourcesDirective, ResourceDirective, TimelineMonth } from '@syncfusion/ej2-vue-schedule';
import { DataManager, WebApiAdaptor } from '@syncfusion/ej2-data';
const dataManager = new DataManager({
url: 'https://services.syncfusion.com/vue/production/api/VirtualEventData',
adaptor: new WebApiAdaptor,
crossDomain: true
});
export default {
name: "App",
components: {
"ejs-schedule": ScheduleComponent,
"e-views": ViewsDirective,
"e-view": ViewDirective,
"e-resources": ResourcesDirective,
"e-resource": ResourceDirective
},
data: function () {
return {
selectedDate: new Date(2023, 3, 1),
enableLazyLoad: true,
group: {
resources: ['Resources']
},
resourceData: generateResourceData(1, 1000, 'Resource'),
eventSettings: { dataSource: dataManager }
}
},
provide: {
schedule: [TimelineMonth]
}
}
</script>
<style>
@import "../node_modules/@syncfusion/ej2-base/styles/material3.css";
@import "../node_modules/@syncfusion/ej2-vue-buttons/styles/material3.css";
@import "../node_modules/@syncfusion/ej2-vue-calendars/styles/material3.css";
@import "../node_modules/@syncfusion/ej2-vue-dropdowns/styles/material3.css";
@import "../node_modules/@syncfusion/ej2-vue-inputs/styles/material3.css";
@import "../node_modules/@syncfusion/ej2-vue-navigations/styles/material3.css";
@import "../node_modules/@syncfusion/ej2-vue-popups/styles/material3.css";
@import "../node_modules/@syncfusion/ej2-vue-schedule/styles/material3.css";
</style>Here’s the server-side controller code that retrieves appointment data based on the resource IDs provided as query parameters:
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System;
using Microsoft.EntityFrameworkCore;
using System.Linq;
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.OData.Query;
namespace LazyLoadingServices.Controllers
{
public class VirtualEventDataController : Controller
{
private readonly EventsContext dbContext;
[HttpGet]
[EnableQuery]
[Route("api/VirtualEventData")]
public IActionResult GetData([FromQuery] Params param)
{
IQueryable<EventData> query = dbContext.Events;
// Filter the appointment data based on the ResourceId query params.
if (!string.IsNullOrEmpty(param.ResourceId))
{
string[] resourceId = param.ResourceId.Split(',');
query = query.Where(data => resourceId.Contains(data.ResourceId.ToString()));
}
return Ok(query.ToList());
}
}
public class Params
{
public DateTime? StartDate { get; set; }
public DateTime? EndDate { get; set; }
public string ResourceId { get; set; }
}
}Note:
- This property is effective when a large number of resources and appointments are bound to the Scheduler.
- This property is applicable only when resource grouping is enabled in the Scheduler.
See Also
For a complete overview of resource scheduling features, visit the Vue Scheduler feature tour page. Explore live examples at Vue Scheduler example to learn how to present and manipulate data.