- Enabling lazy loading for appointments
- See Also
Contact Support
Virtual scrolling in Angular Schedule component
18 Oct 202517 minutes to read
Virtual scrolling support in the Scheduler component enhances performance when working with a substantial number of resources and events. This feature allows large sets of resources and events to load dynamically in the timeline views as users scroll, resulting in a seamless user experience. Enable virtual scrolling by setting the allowVirtualScrolling property to true within the specific timeline view settings. In the Agenda view, enable the same property in the agenda view configuration to allow virtual loading of events.
import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { ScheduleModule } from '@syncfusion/ej2-angular-schedule'
import { ButtonModule } from '@syncfusion/ej2-angular-buttons'
import { DayService, WeekService, WorkWeekService, MonthService, AgendaService, MonthAgendaService} from '@syncfusion/ej2-angular-schedule'
import { Component } from '@angular/core';
import { EventSettingsModel, TimelineMonthService, TimelineYearService, GroupModel } from '@syncfusion/ej2-angular-schedule';
@Component({
imports: [
ScheduleModule,
ButtonModule
],
providers: [DayService,
WeekService,
WorkWeekService,
MonthService,
AgendaService,
MonthAgendaService,
TimelineMonthService, TimelineYearService],
standalone: true,
selector: 'app-root',
// specifies the template string for the Schedule component
template: `<ejs-schedule width='100%' cssClass='virtual-scrolling' height='550px' [group]="group" [selectedDate]="selectedDate" [eventSettings]="eventSettings">
<e-resources>
<e-resource field='ResourceId' title='Resource' [dataSource]='resourceDataSource' [allowMultiple]='allowMultiple'
name='Resources' textField='Text' idField='Id' colorField='Color'>
</e-resource>
</e-resources>
<e-views>
<e-view option="TimelineMonth" [allowVirtualScrolling]="virtualscroll" isSelected=true></e-view>
<e-view option="TimelineYear" [allowVirtualScrolling]="virtualscroll" orientation="Vertical"></e-view>
</e-views>
</ejs-schedule>`
})
export class AppComponent {
public selectedDate: Date = new Date(2018, 4, 1);
public group: GroupModel = { byGroupID: false, resources: ['Resources'] };
public allowMultiple: boolean = true;
public resourceDataSource: Object[] = this.generateResourceData(1, 300, 'Resource');
public eventSettings: EventSettingsModel = { dataSource: this.generateStaticEvents(new Date(2018, 4, 1), 300, 12) };
public virtualscroll: boolean = true;
private generateStaticEvents(start: Date, resCount: number, overlapCount: number): Object[] {
let data: Object[] = [];
let id: number = 1;
for (let i: number = 0; i < resCount; i++) {
let randomCollection: number[] = [];
let random: number = 0;
for (let j: number = 0; j < overlapCount; j++) {
random = Math.floor(Math.random() * (30));
random = (random === 0) ? 1 : random;
if (randomCollection.indexOf(random) !== -1 || randomCollection.indexOf(random + 2) !== -1 ||
randomCollection.indexOf(random - 2) !== -1) {
random += (Math.max.apply(null, randomCollection) + 10);
}
for (let k: number = 1; k <= 2; k++) {
randomCollection.push(random + k);
}
let startDate: Date = new Date(start.getFullYear(), start.getMonth(), random);
startDate = new Date(startDate.getTime() + (((random % 10) * 10) * (1000 * 60)));
let endDate: Date = new Date(startDate.getTime() + ((1440 + 30) * (1000 * 60)));
data.push({
Id: id,
Subject: 'Event #' + id,
StartTime: startDate,
EndTime: endDate,
IsAllDay: (id % 10) ? false : true,
ResourceId: i + 1
});
id++;
}
}
return data;
};
private generateResourceData(startId: number, endId: number, text: string): Object[] {
let data: { [key: string]: Object }[] = [];
let colors: string[] = [
'#ff8787', '#9775fa', '#748ffc', '#3bc9db', '#69db7c',
'#fdd835', '#748ffc', '#9775fa', '#df5286', '#7fa900',
'#fec200', '#5978ee', '#00bdae', '#ea80fc'
];
for (let a: number = startId; a <= endId; a++) {
let n: number = Math.floor(Math.random() * colors.length);
data.push({
Id: a,
Text: text + ' ' + a,
Color: colors[n]
});
}
return data;
}
}import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
Currently, virtual loading of resources and events is supported only in the
TimelineDay,TimelineWeek,TimelineWorkWeek,TimelineMonth, andTimelineYearviews with vertical orientation. Future updates will extend virtual loading support to additional applicable Scheduler views.
Enabling lazy loading for appointments
The lazy loading feature provides an efficient approach for loading appointment data into the Scheduler on-demand. This allows large volumes of appointments to be loaded without performance issues.
By default, the Scheduler retrieves all relevant appointments within the current date range from the server. When lazy loading is enabled, the Scheduler sends queries to the server to retrieve appointments only for resources currently displayed as a result of scroll actions. These queries include the resource IDs and the current date range as a comma-separated string. On the server, these resource IDs are parsed to filter and serve only the necessary appointments for rendering in the Scheduler.
With this feature enabled, the Scheduler fetches events from remote services solely for the appointments currently visible in the viewport, optimizing data retrieval. Additional appointment data is fetched from the server on-demand as new resources enter the viewport during scrolling.
Enable this feature by setting the enableLazyLoading property to true in the appropriate view settings.
import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { ScheduleModule, TimelineMonthService, RecurrenceEditorModule } from '@syncfusion/ej2-angular-schedule'
import { ButtonModule } from '@syncfusion/ej2-angular-buttons'
import { Component } from '@angular/core';
import { EventSettingsModel, GroupModel } from '@syncfusion/ej2-angular-schedule';
import { DataManager, WebApiAdaptor } from '@syncfusion/ej2-data';
@Component({
imports: [
ScheduleModule,
RecurrenceEditorModule,
ButtonModule
],
standalone: true,
selector: 'app-root',
providers: [TimelineMonthService],
// specifies the template string for the Schedule component
template: `<ejs-schedule width='100%' height='550px' [readonly]='readonly' [group]="group" [selectedDate]="selectedDate" [eventSettings]="eventSettings">
<e-resources>
<e-resource field='ResourceId' title='Resource' [dataSource]='resourceDataSource'
name='Resources' textField='Text' idField='Id' colorField='Color'>
</e-resource>
</e-resources>
<e-views>
<e-view option="TimelineMonth" [enableLazyLoading]="enableLazyLoad" isSelected=true></e-view>
</e-views>
</ejs-schedule>`
})
export class AppComponent {
public selectedDate: Date = new Date(2023, 3, 1);
public readonly: boolean = true;
public group: GroupModel = { resources: ['Resources'] };
public resourceDataSource: Object[] = this.generateResourceData(1, 1000, 'Resource');
private dataManager: DataManager = new DataManager({
url: 'https://services.syncfusion.com/angular/production/api/VirtualEventData',
adaptor: new WebApiAdaptor(),
crossDomain: true
});
public eventSettings: EventSettingsModel = { dataSource: this.dataManager };
public enableLazyLoad: boolean = true;
private generateResourceData(startId: number, endId: number, text: string): Object[] {
let data: { [key: string]: Object }[] = [];
let colors: string[] = [
'#ff8787', '#9775fa', '#748ffc', '#3bc9db', '#69db7c',
'#fdd835', '#748ffc', '#9775fa', '#df5286', '#7fa900',
'#fec200', '#5978ee', '#00bdae', '#ea80fc'
];
for (let a: number = startId; a <= endId; a++) {
let n: number = Math.floor(Math.random() * colors.length);
data.push({
Id: a,
Text: text + ' ' + a,
Color: colors[n]
});
}
return data;
}
}import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));The following server-side controller code demonstrates how to retrieve appointment data based on resource IDs received 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:
- The property will be effective, when large number of resources and appointments bound to the Scheduler.
- This property is applicable only when resource grouping is enabled in Scheduler.
See Also
You can refer to our Angular Scheduler feature tour page for its groundbreaking feature representations. You can also explore our Angular Scheduler example to knows how to present and manipulate data.