Web Components Grid Remote Data Operations
By default, the IgcGridComponent
uses its own logic for performing data operations.
You can perform these tasks remotely and feed the resulting data to the IgcGridComponent
by taking advantage of certain inputs and events, which are exposed by the IgcGridComponent
.
Infinite Scroll
A popular design for scenarios requiring fetching data by chunks from an end-point is the so-called infinite scroll. For data grids, it is characterized by continuous increase of the loaded data triggered by the end-user scrolling all the way to the bottom. The next paragraphs explain how you can use the available API to easily achieve infinite scrolling in IgcGridComponent
.
To implement infinite scroll, you have to fetch the data in chunks. The data that is already fetched should be stored locally and you have to determine the length of a chunk and how many chunks there are. You also have to keep a track of the last visible data row index in the grid. In this way, using the StartIndex
and ChunkSize
properties, you can determine if the user scrolls up and you have to show them already fetched data or scrolls down and you have to fetch more data from the end-point.
The first thing to do is fetch the first chunk of the data. Setting the totalItemCount
property is important, as it allows the grid to size its scrollbar correctly.
Additionally, you have to subscribe to the DataPreLoad
output, so that you can provide the data needed by the grid when it tries to display a different chunk, rather than the currently loaded one. In the event handler, you have to determine whether to fetch new data or return data, that's already cached locally.
Infinite Scroll Demo
export class NwindDataItem {
public constructor(init: Partial<NwindDataItem>) {
Object.assign(this, init);
}
public ProductID: number;
public ProductName: string;
public SupplierID: number;
public CategoryID: number;
public QuantityPerUnit: string;
public UnitPrice: number;
public UnitsInStock: number;
public UnitsOnOrder: number;
public ReorderLevel: number;
public Discontinued: boolean;
public OrderDate: string;
public Rating: number;
public Locations: NwindDataItem_LocationsItem[];
}
export class NwindDataItem_LocationsItem {
public constructor(init: Partial<NwindDataItem_LocationsItem>) {
Object.assign(this, init);
}
public Shop: string;
public LastInventory: string;
}
export class NwindData extends Array<NwindDataItem> {
public constructor() {
super();
this.push(new NwindDataItem({ "ProductID": 1, "ProductName": "Chai", "SupplierID": 1, "CategoryID": 1, "QuantityPerUnit": "10 boxes x 20 bags", "UnitPrice": 18.0000, "UnitsInStock": 39, "UnitsOnOrder": 0, "ReorderLevel": 10, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 2, "ProductName": "Chang", "SupplierID": 1, "CategoryID": 1, "QuantityPerUnit": "24 - 12 oz bottles", "UnitPrice": 19.0000, "UnitsInStock": 17, "UnitsOnOrder": 40, "ReorderLevel": 25, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 3, "ProductName": "Aniseed Syrup", "SupplierID": 1, "CategoryID": 2, "QuantityPerUnit": "12 - 550 ml bottles", "UnitPrice": 10.0000, "UnitsInStock": 13, "UnitsOnOrder": 70, "ReorderLevel": 25, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 4, "ProductName": "Chef Anton's Cajun Seasoning", "SupplierID": 2, "CategoryID": 2, "QuantityPerUnit": "48 - 6 oz jars", "UnitPrice": 22.0000, "UnitsInStock": 53, "UnitsOnOrder": 0, "ReorderLevel": 0, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 5, "ProductName": "Chef Anton's Gumbo Mix", "SupplierID": 2, "CategoryID": 2, "QuantityPerUnit": "36 boxes", "UnitPrice": 21.3500, "UnitsInStock": 0, "UnitsOnOrder": 0, "ReorderLevel": 0, "Discontinued": true }));
this.push(new NwindDataItem({ "ProductID": 6, "ProductName": "Grandma's Boysenberry Spread", "SupplierID": 3, "CategoryID": 2, "QuantityPerUnit": "12 - 8 oz jars", "UnitPrice": 25.0000, "UnitsInStock": 120, "UnitsOnOrder": 0, "ReorderLevel": 25, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 7, "ProductName": "Uncle Bob's Organic Dried Pears", "SupplierID": 3, "CategoryID": 7, "QuantityPerUnit": "12 - 1 lb pkgs.", "UnitPrice": 30.0000, "UnitsInStock": 15, "UnitsOnOrder": 0, "ReorderLevel": 10, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 8, "ProductName": "Northwoods Cranberry Sauce", "SupplierID": 3, "CategoryID": 2, "QuantityPerUnit": "12 - 12 oz jars", "UnitPrice": 40.0000, "UnitsInStock": 6, "UnitsOnOrder": 0, "ReorderLevel": 0, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 9, "ProductName": "Mishi Kobe Niku", "SupplierID": 4, "CategoryID": 6, "QuantityPerUnit": "18 - 500 g pkgs.", "UnitPrice": 97.0000, "UnitsInStock": 29, "UnitsOnOrder": 0, "ReorderLevel": 0, "Discontinued": true }));
this.push(new NwindDataItem({ "ProductID": 10, "ProductName": "Ikura", "SupplierID": 4, "CategoryID": 8, "QuantityPerUnit": "12 - 200 ml jars", "UnitPrice": 31.0000, "UnitsInStock": 31, "UnitsOnOrder": 0, "ReorderLevel": 0, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 11, "ProductName": "Queso Cabrales", "SupplierID": 5, "CategoryID": 4, "QuantityPerUnit": "1 kg pkg.", "UnitPrice": 21.0000, "UnitsInStock": 22, "UnitsOnOrder": 30, "ReorderLevel": 30, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 12, "ProductName": "Queso Manchego La Pastora", "SupplierID": 5, "CategoryID": 4, "QuantityPerUnit": "10 - 500 g pkgs.", "UnitPrice": 38.0000, "UnitsInStock": 86, "UnitsOnOrder": 0, "ReorderLevel": 0, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 13, "ProductName": "Konbu", "SupplierID": 6, "CategoryID": 8, "QuantityPerUnit": "2 kg box", "UnitPrice": 6.0000, "UnitsInStock": 24, "UnitsOnOrder": 0, "ReorderLevel": 5, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 14, "ProductName": "Tofu", "SupplierID": 6, "CategoryID": 7, "QuantityPerUnit": "40 - 100 g pkgs.", "UnitPrice": 23.2500, "UnitsInStock": 35, "UnitsOnOrder": 0, "ReorderLevel": 0, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 15, "ProductName": "Genen Shouyu", "SupplierID": 6, "CategoryID": 2, "QuantityPerUnit": "24 - 250 ml bottles", "UnitPrice": 15.5000, "UnitsInStock": 39, "UnitsOnOrder": 0, "ReorderLevel": 5, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 16, "ProductName": "Pavlova", "SupplierID": 7, "CategoryID": 3, "QuantityPerUnit": "32 - 500 g boxes", "UnitPrice": 17.4500, "UnitsInStock": 29, "UnitsOnOrder": 0, "ReorderLevel": 10, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 17, "ProductName": "Alice Mutton", "SupplierID": 7, "CategoryID": 6, "QuantityPerUnit": "20 - 1 kg tins", "UnitPrice": 39.0000, "UnitsInStock": 0, "UnitsOnOrder": 0, "ReorderLevel": 0, "Discontinued": true }));
this.push(new NwindDataItem({ "ProductID": 18, "ProductName": "Carnarvon Tigers", "SupplierID": 7, "CategoryID": 8, "QuantityPerUnit": "16 kg pkg.", "UnitPrice": 62.5000, "UnitsInStock": 42, "UnitsOnOrder": 0, "ReorderLevel": 0, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 19, "ProductName": "Teatime Chocolate Biscuits", "SupplierID": 8, "CategoryID": 3, "QuantityPerUnit": "10 boxes x 12 pieces", "UnitPrice": 9.2000, "UnitsInStock": 25, "UnitsOnOrder": 0, "ReorderLevel": 5, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 20, "ProductName": "Sir Rodney's Marmalade", "SupplierID": 8, "CategoryID": 3, "QuantityPerUnit": "30 gift boxes", "UnitPrice": 81.0000, "UnitsInStock": 40, "UnitsOnOrder": 0, "ReorderLevel": 0, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 21, "ProductName": "Sir Rodney's Scones", "SupplierID": 8, "CategoryID": 3, "QuantityPerUnit": "24 pkgs. x 4 pieces", "UnitPrice": 10.0000, "UnitsInStock": 3, "UnitsOnOrder": 40, "ReorderLevel": 5, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 22, "ProductName": "Gustaf's Kn\u00e4ckebr\u00f6d", "SupplierID": 9, "CategoryID": 5, "QuantityPerUnit": "24 - 500 g pkgs.", "UnitPrice": 21.0000, "UnitsInStock": 104, "UnitsOnOrder": 0, "ReorderLevel": 25, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 23, "ProductName": "Tunnbr\u00f6d", "SupplierID": 9, "CategoryID": 5, "QuantityPerUnit": "12 - 250 g pkgs.", "UnitPrice": 9.0000, "UnitsInStock": 61, "UnitsOnOrder": 0, "ReorderLevel": 25, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 24, "ProductName": "Guaran\u00e1 Fant\u00e1stica", "SupplierID": 10, "CategoryID": 1, "QuantityPerUnit": "12 - 355 ml cans", "UnitPrice": 4.5000, "UnitsInStock": 20, "UnitsOnOrder": 0, "ReorderLevel": 0, "Discontinued": true }));
this.push(new NwindDataItem({ "ProductID": 25, "ProductName": "NuNuCa Nu\u00df-Nougat-Creme", "SupplierID": 11, "CategoryID": 3, "QuantityPerUnit": "20 - 450 g glasses", "UnitPrice": 14.0000, "UnitsInStock": 76, "UnitsOnOrder": 0, "ReorderLevel": 30, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 26, "ProductName": "Gumb\u00e4r Gummib\u00e4rchen", "SupplierID": 11, "CategoryID": 3, "QuantityPerUnit": "100 - 250 g bags", "UnitPrice": 31.2300, "UnitsInStock": 15, "UnitsOnOrder": 0, "ReorderLevel": 0, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 27, "ProductName": "Schoggi Schokolade", "SupplierID": 11, "CategoryID": 3, "QuantityPerUnit": "100 - 100 g pieces", "UnitPrice": 43.9000, "UnitsInStock": 49, "UnitsOnOrder": 0, "ReorderLevel": 30, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 28, "ProductName": "R\u00f6ssle Sauerkraut", "SupplierID": 12, "CategoryID": 7, "QuantityPerUnit": "25 - 825 g cans", "UnitPrice": 45.6000, "UnitsInStock": 26, "UnitsOnOrder": 0, "ReorderLevel": 0, "Discontinued": true }));
this.push(new NwindDataItem({ "ProductID": 29, "ProductName": "Th\u00fcringer Rostbratwurst", "SupplierID": 12, "CategoryID": 6, "QuantityPerUnit": "50 bags x 30 sausgs.", "UnitPrice": 123.7900, "UnitsInStock": 0, "UnitsOnOrder": 0, "ReorderLevel": 0, "Discontinued": true }));
this.push(new NwindDataItem({ "ProductID": 30, "ProductName": "Nord-Ost Matjeshering", "SupplierID": 13, "CategoryID": 8, "QuantityPerUnit": "10 - 200 g glasses", "UnitPrice": 25.8900, "UnitsInStock": 10, "UnitsOnOrder": 0, "ReorderLevel": 15, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 31, "ProductName": "Gorgonzola Telino", "SupplierID": 14, "CategoryID": 4, "QuantityPerUnit": "12 - 100 g pkgs", "UnitPrice": 12.5000, "UnitsInStock": 0, "UnitsOnOrder": 70, "ReorderLevel": 20, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 32, "ProductName": "Mascarpone Fabioli", "SupplierID": 14, "CategoryID": 4, "QuantityPerUnit": "24 - 200 g pkgs.", "UnitPrice": 32.0000, "UnitsInStock": 9, "UnitsOnOrder": 40, "ReorderLevel": 25, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 33, "ProductName": "Geitost", "SupplierID": 15, "CategoryID": 4, "QuantityPerUnit": "500 g", "UnitPrice": 2.5000, "UnitsInStock": 112, "UnitsOnOrder": 0, "ReorderLevel": 20, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 34, "ProductName": "Sasquatch Ale", "SupplierID": 16, "CategoryID": 1, "QuantityPerUnit": "24 - 12 oz bottles", "UnitPrice": 14.0000, "UnitsInStock": 111, "UnitsOnOrder": 0, "ReorderLevel": 15, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 35, "ProductName": "Steeleye Stout", "SupplierID": 16, "CategoryID": 1, "QuantityPerUnit": "24 - 12 oz bottles", "UnitPrice": 18.0000, "UnitsInStock": 20, "UnitsOnOrder": 0, "ReorderLevel": 15, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 36, "ProductName": "Inlagd Sill", "SupplierID": 17, "CategoryID": 8, "QuantityPerUnit": "24 - 250 g jars", "UnitPrice": 19.0000, "UnitsInStock": 112, "UnitsOnOrder": 0, "ReorderLevel": 20, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 37, "ProductName": "Gravad lax", "SupplierID": 17, "CategoryID": 8, "QuantityPerUnit": "12 - 500 g pkgs.", "UnitPrice": 26.0000, "UnitsInStock": 11, "UnitsOnOrder": 50, "ReorderLevel": 25, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 38, "ProductName": "C\u00f4te de Blaye", "SupplierID": 18, "CategoryID": 1, "QuantityPerUnit": "12 - 75 cl bottles", "UnitPrice": 263.5000, "UnitsInStock": 17, "UnitsOnOrder": 0, "ReorderLevel": 15, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 39, "ProductName": "Chartreuse verte", "SupplierID": 18, "CategoryID": 1, "QuantityPerUnit": "750 cc per bottle", "UnitPrice": 18.0000, "UnitsInStock": 69, "UnitsOnOrder": 0, "ReorderLevel": 5, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 40, "ProductName": "Boston Crab Meat", "SupplierID": 19, "CategoryID": 8, "QuantityPerUnit": "24 - 4 oz tins", "UnitPrice": 18.4000, "UnitsInStock": 123, "UnitsOnOrder": 0, "ReorderLevel": 30, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 41, "ProductName": "Jack's New England Clam Chowder", "SupplierID": 19, "CategoryID": 8, "QuantityPerUnit": "12 - 12 oz cans", "UnitPrice": 9.6500, "UnitsInStock": 85, "UnitsOnOrder": 0, "ReorderLevel": 10, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 42, "ProductName": "Singaporean Hokkien Fried Mee", "SupplierID": 20, "CategoryID": 5, "QuantityPerUnit": "32 - 1 kg pkgs.", "UnitPrice": 14.0000, "UnitsInStock": 26, "UnitsOnOrder": 0, "ReorderLevel": 0, "Discontinued": true }));
this.push(new NwindDataItem({ "ProductID": 43, "ProductName": "Ipoh Coffee", "SupplierID": 20, "CategoryID": 1, "QuantityPerUnit": "16 - 500 g tins", "UnitPrice": 46.0000, "UnitsInStock": 17, "UnitsOnOrder": 10, "ReorderLevel": 25, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 44, "ProductName": "Gula Malacca", "SupplierID": 20, "CategoryID": 2, "QuantityPerUnit": "20 - 2 kg bags", "UnitPrice": 19.4500, "UnitsInStock": 27, "UnitsOnOrder": 0, "ReorderLevel": 15, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 45, "ProductName": "Rogede sild", "SupplierID": 21, "CategoryID": 8, "QuantityPerUnit": "1k pkg.", "UnitPrice": 9.5000, "UnitsInStock": 5, "UnitsOnOrder": 70, "ReorderLevel": 15, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 46, "ProductName": "Spegesild", "SupplierID": 21, "CategoryID": 8, "QuantityPerUnit": "4 - 450 g glasses", "UnitPrice": 12.0000, "UnitsInStock": 95, "UnitsOnOrder": 0, "ReorderLevel": 0, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 47, "ProductName": "Zaanse koeken", "SupplierID": 22, "CategoryID": 3, "QuantityPerUnit": "10 - 4 oz boxes", "UnitPrice": 9.5000, "UnitsInStock": 36, "UnitsOnOrder": 0, "ReorderLevel": 0, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 48, "ProductName": "Chocolade", "SupplierID": 22, "CategoryID": 3, "QuantityPerUnit": "10 pkgs.", "UnitPrice": 12.7500, "UnitsInStock": 15, "UnitsOnOrder": 70, "ReorderLevel": 25, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 49, "ProductName": "Maxilaku", "SupplierID": 23, "CategoryID": 3, "QuantityPerUnit": "24 - 50 g pkgs.", "UnitPrice": 20.0000, "UnitsInStock": 10, "UnitsOnOrder": 60, "ReorderLevel": 15, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 50, "ProductName": "Valkoinen suklaa", "SupplierID": 23, "CategoryID": 3, "QuantityPerUnit": "12 - 100 g bars", "UnitPrice": 16.2500, "UnitsInStock": 65, "UnitsOnOrder": 0, "ReorderLevel": 30, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 51, "ProductName": "Manjimup Dried Apples", "SupplierID": 24, "CategoryID": 7, "QuantityPerUnit": "50 - 300 g pkgs.", "UnitPrice": 53.0000, "UnitsInStock": 20, "UnitsOnOrder": 0, "ReorderLevel": 10, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 52, "ProductName": "Filo Mix", "SupplierID": 24, "CategoryID": 5, "QuantityPerUnit": "16 - 2 kg boxes", "UnitPrice": 7.0000, "UnitsInStock": 38, "UnitsOnOrder": 0, "ReorderLevel": 25, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 53, "ProductName": "Perth Pasties", "SupplierID": 24, "CategoryID": 6, "QuantityPerUnit": "48 pieces", "UnitPrice": 32.8000, "UnitsInStock": 0, "UnitsOnOrder": 0, "ReorderLevel": 0, "Discontinued": true }));
this.push(new NwindDataItem({ "ProductID": 54, "ProductName": "Tourti\u00e8re", "SupplierID": 25, "CategoryID": 6, "QuantityPerUnit": "16 pies", "UnitPrice": 7.4500, "UnitsInStock": 21, "UnitsOnOrder": 0, "ReorderLevel": 10, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 55, "ProductName": "P\u00e2t\u00e9 chinois", "SupplierID": 25, "CategoryID": 6, "QuantityPerUnit": "24 boxes x 2 pies", "UnitPrice": 24.0000, "UnitsInStock": 115, "UnitsOnOrder": 0, "ReorderLevel": 20, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 56, "ProductName": "Gnocchi di nonna Alice", "SupplierID": 26, "CategoryID": 5, "QuantityPerUnit": "24 - 250 g pkgs.", "UnitPrice": 38.0000, "UnitsInStock": 21, "UnitsOnOrder": 10, "ReorderLevel": 30, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 57, "ProductName": "Ravioli Angelo", "SupplierID": 26, "CategoryID": 5, "QuantityPerUnit": "24 - 250 g pkgs.", "UnitPrice": 19.5000, "UnitsInStock": 36, "UnitsOnOrder": 0, "ReorderLevel": 20, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 58, "ProductName": "Escargots de Bourgogne", "SupplierID": 27, "CategoryID": 8, "QuantityPerUnit": "24 pieces", "UnitPrice": 13.2500, "UnitsInStock": 62, "UnitsOnOrder": 0, "ReorderLevel": 20, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 59, "ProductName": "Raclette Courdavault", "SupplierID": 28, "CategoryID": 4, "QuantityPerUnit": "5 kg pkg.", "UnitPrice": 55.0000, "UnitsInStock": 79, "UnitsOnOrder": 0, "ReorderLevel": 0, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 60, "ProductName": "Camembert Pierrot", "SupplierID": 28, "CategoryID": 4, "QuantityPerUnit": "15 - 300 g rounds", "UnitPrice": 34.0000, "UnitsInStock": 19, "UnitsOnOrder": 0, "ReorderLevel": 0, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 61, "ProductName": "Sirop d'\u00e9rable", "SupplierID": 29, "CategoryID": 2, "QuantityPerUnit": "24 - 500 ml bottles", "UnitPrice": 28.5000, "UnitsInStock": 113, "UnitsOnOrder": 0, "ReorderLevel": 25, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 62, "ProductName": "Tarte au sucre", "SupplierID": 29, "CategoryID": 3, "QuantityPerUnit": "48 pies", "UnitPrice": 49.3000, "UnitsInStock": 17, "UnitsOnOrder": 0, "ReorderLevel": 0, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 63, "ProductName": "Vegie-spread", "SupplierID": 7, "CategoryID": 2, "QuantityPerUnit": "15 - 625 g jars", "UnitPrice": 43.9000, "UnitsInStock": 24, "UnitsOnOrder": 0, "ReorderLevel": 5, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 64, "ProductName": "Wimmers gute Semmelkn\u00f6del", "SupplierID": 12, "CategoryID": 5, "QuantityPerUnit": "20 bags x 4 pieces", "UnitPrice": 33.2500, "UnitsInStock": 22, "UnitsOnOrder": 80, "ReorderLevel": 30, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 65, "ProductName": "Louisiana Fiery Hot Pepper Sauce", "SupplierID": 2, "CategoryID": 2, "QuantityPerUnit": "32 - 8 oz bottles", "UnitPrice": 21.0500, "UnitsInStock": 76, "UnitsOnOrder": 0, "ReorderLevel": 0, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 66, "ProductName": "Louisiana Hot Spiced Okra", "SupplierID": 2, "CategoryID": 2, "QuantityPerUnit": "24 - 8 oz jars", "UnitPrice": 17.0000, "UnitsInStock": 4, "UnitsOnOrder": 100, "ReorderLevel": 20, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 67, "ProductName": "Laughing Lumberjack Lager", "SupplierID": 16, "CategoryID": 1, "QuantityPerUnit": "24 - 12 oz bottles", "UnitPrice": 14.0000, "UnitsInStock": 52, "UnitsOnOrder": 0, "ReorderLevel": 10, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 68, "ProductName": "Scottish Longbreads", "SupplierID": 8, "CategoryID": 3, "QuantityPerUnit": "10 boxes x 8 pieces", "UnitPrice": 12.5000, "UnitsInStock": 6, "UnitsOnOrder": 10, "ReorderLevel": 15, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 69, "ProductName": "Gudbrandsdalsost", "SupplierID": 15, "CategoryID": 4, "QuantityPerUnit": "10 kg pkg.", "UnitPrice": 36.0000, "UnitsInStock": 26, "UnitsOnOrder": 0, "ReorderLevel": 15, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 70, "ProductName": "Outback Lager", "SupplierID": 7, "CategoryID": 1, "QuantityPerUnit": "24 - 355 ml bottles", "UnitPrice": 15.0000, "UnitsInStock": 15, "UnitsOnOrder": 10, "ReorderLevel": 30, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 71, "ProductName": "Flotemysost", "SupplierID": 15, "CategoryID": 4, "QuantityPerUnit": "10 - 500 g pkgs.", "UnitPrice": 21.5000, "UnitsInStock": 26, "UnitsOnOrder": 0, "ReorderLevel": 0, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 72, "ProductName": "Mozzarella di Giovanni", "SupplierID": 14, "CategoryID": 4, "QuantityPerUnit": "24 - 200 g pkgs.", "UnitPrice": 34.8000, "UnitsInStock": 14, "UnitsOnOrder": 0, "ReorderLevel": 0, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 73, "ProductName": "R\u00f6d Kaviar", "SupplierID": 17, "CategoryID": 8, "QuantityPerUnit": "24 - 150 g jars", "UnitPrice": 15.0000, "UnitsInStock": 101, "UnitsOnOrder": 0, "ReorderLevel": 5, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 74, "ProductName": "Longlife Tofu", "SupplierID": 4, "CategoryID": 7, "QuantityPerUnit": "5 kg pkg.", "UnitPrice": 10.0000, "UnitsInStock": 4, "UnitsOnOrder": 20, "ReorderLevel": 5, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 75, "ProductName": "Rh\u00f6nbr\u00e4u Klosterbier", "SupplierID": 12, "CategoryID": 1, "QuantityPerUnit": "24 - 0.5 l bottles", "UnitPrice": 7.7500, "UnitsInStock": 125, "UnitsOnOrder": 0, "ReorderLevel": 25, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 76, "ProductName": "Lakkalik\u00f6\u00f6ri", "SupplierID": 23, "CategoryID": 1, "QuantityPerUnit": "500 ml", "UnitPrice": 18.0000, "UnitsInStock": 57, "UnitsOnOrder": 0, "ReorderLevel": 20, "Discontinued": false }));
this.push(new NwindDataItem({ "ProductID": 77, "ProductName": "Original Frankfurter gr\u00fcne So\u00dfe", "SupplierID": 12, "CategoryID": 2, "QuantityPerUnit": "12 boxes", "UnitPrice": 13.0000, "UnitsInStock": 32, "UnitsOnOrder": 0, "ReorderLevel": 15, "Discontinued": false }));
}
}
tsimport { IgcForOfState } from "igniteui-webcomponents-grids/grids";
import { NwindData, NwindDataItem } from "./NwindData";
import { BehaviorSubject, Observable } from 'rxjs';
const DATA_URL: string = 'https://services.odata.org/V4/Northwind/Northwind.svc/Products';
export class RemoteNwindService {
// public remoteData: NwindDataItem[];
// constructor() {
// this.remoteData = new NwindData();
// }
// public getData(index?: number, perPage?: number): Promise<NwindDataItem[]> {
// const data = this.remoteData.slice(index * perPage, index * perPage + perPage);
// return new Promise((resolve, reject) => {
// setTimeout(resolve, 500, data);
// });
// }
// public getDataLength(): Promise<number> {
// return Promise.resolve(this.remoteData.length);
// }`
public data: Observable<any[]>;
private _data: BehaviorSubject<any[]>;
private _cachedData = <any>[];
private _prevRequestChunk: number;
constructor() {
this._data = new BehaviorSubject([]);
this.data = this._data.asObservable();
}
public get cachedData() {
return this._cachedData;
}
public async loadDataForPage(page: number, pageSize: number, callback?: (arg: any) => void) {
const url = this._buildDataUrl(page, pageSize)
const response = await fetch(url);
const data = await response.json();
const startIndex = (page - 1) * pageSize;
this._updateData(data, startIndex);
this._data.next(data);
callback({ data });
}
public getCachedData(virtualizationArgs: IgcForOfState) {
const virtArgsEndIndex = virtualizationArgs.startIndex + virtualizationArgs.chunkSize;
let data = [];
if (virtArgsEndIndex > this._cachedData.length) {
data = this._cachedData.slice(this._cachedData.length - this._prevRequestChunk + 1);
} else {
data = this._cachedData.slice(virtualizationArgs.startIndex, virtArgsEndIndex);
this._prevRequestChunk = virtualizationArgs.chunkSize;
}
return data;
}
private _updateData(data: any, startIndex: number) {
for (let i = 0; i < data.value.length; i++) {
this._cachedData[i + startIndex] = data.value[i];
}
}
private _buildDataUrl(page: number, pageSize: number): string {
let baseQueryString = `${DATA_URL}?$count=true&`;
const skip = (page - 1) * pageSize;
const pageQuery = `$skip=${skip}&$top=${pageSize}`;
baseQueryString += pageQuery;
return baseQueryString;
}
}
tsimport { IgcPropertyEditorPanelModule } from 'igniteui-webcomponents-layouts';
import 'igniteui-webcomponents-grids/grids/combined';
import { ComponentRenderer, PropertyEditorPanelDescriptionModule, WebGridDescriptionModule } from 'igniteui-webcomponents-core';
import { IgcGridComponent, IgcColumnComponent, IgcForOfState } from 'igniteui-webcomponents-grids/grids';
import { NwindDataItem, NwindDataItem_LocationsItem, NwindData } from './NwindData';
import "igniteui-webcomponents-grids/grids/themes/light/bootstrap.css";
import { ModuleManager } from 'igniteui-webcomponents-core';
import { RemoteNwindService } from './NwindService';
ModuleManager.register(
IgcPropertyEditorPanelModule
);
export class Sample {
private grid: IgcGridComponent;
public remoteData: any;
private page = 1;
private pageSize = 10;
private totalPageCount = 0;
private totalItems = 0;
private iD: IgcColumnComponent
private productName: IgcColumnComponent
private quantityPerUnit: IgcColumnComponent
private unitPrice: IgcColumnComponent
private orderDate: IgcColumnComponent
private discontinued: IgcColumnComponent
private _bind: () => void;
private remoteService = new RemoteNwindService();
constructor() {
var grid = this.grid = document.getElementById('grid') as IgcGridComponent;
var iD = this.iD = document.getElementById('ID') as IgcColumnComponent;
var productName = this.productName = document.getElementById('ProductName') as IgcColumnComponent;
var quantityPerUnit = this.quantityPerUnit = document.getElementById('QuantityPerUnit') as IgcColumnComponent;
var unitPrice = this.unitPrice = document.getElementById('UnitPrice') as IgcColumnComponent;
var orderDate = this.orderDate = document.getElementById('OrderDate') as IgcColumnComponent;
var discontinued = this.discontinued = document.getElementById('Discontinued') as IgcColumnComponent;
this.grid.isLoading = true;
// load 1 page of data with the size of a data view and a half
const dataViewSize = 9.6; // grid.height / grid.rowHeight;
this.pageSize = Math.floor(dataViewSize * 1.5);
this.remoteService.loadDataForPage(this.page, this.pageSize, (request) => {
if (request.data) {
this.grid.data = this.remoteService.getCachedData({ startIndex: 0, chunkSize: 10 });
this.grid.totalItemCount = this.page * this.pageSize;
this.totalItems = request.data['@odata.count'];
this.totalPageCount = Math.ceil(this.totalItems / this.pageSize);
this.grid.isLoading = false;
}
});
this._bind = () => {
this.grid.addEventListener('dataPreLoad', (e) => {
this.handlePreLoad(e as CustomEvent<IgcForOfState>);
});
}
this._bind();
}
private _nwindData: NwindData = null;
public get nwindData(): NwindData {
if (this._nwindData == null) {
this._nwindData = new NwindData();
}
return this._nwindData;
}
public handlePreLoad(e: CustomEvent<IgcForOfState>) {
const isLastChunk = this.grid.totalItemCount === e.detail.startIndex + e.detail.chunkSize;
// when last chunk reached load another page of data
if (isLastChunk) {
if (this.totalPageCount === this.page) {
this.grid.data = this.remoteService.getCachedData(e.detail);
return;
}
this.page++;
this.grid.isLoading = true;
this.remoteService.loadDataForPage(this.page, this.pageSize, (request) => {
if (request.data) {
this.grid.totalItemCount = Math.min(this.page * this.pageSize, this.totalItems);
this.grid.data = this.remoteService.getCachedData(e.detail);
this.grid.isLoading = false;
}
});
} else {
this.grid.data = this.remoteService.getCachedData(e.detail);
}
}
}
new Sample();
ts<!DOCTYPE html>
<html>
<head>
<title>Sample | Ignite UI | Web Components | infragistics</title>
<meta charset="UTF-8" />
<link rel="shortcut icon" href="https://static.infragistics.com/xplatform/images/browsers/wc.png" >
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Kanit&display=swap" />
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Titillium Web" />
<link rel="stylesheet" href="https://static.infragistics.com/xplatform/css/samples/shared.v8.css" />
<link rel="stylesheet" href="/src/index.css" type="text/css" />
</head>
<body>
<div id="root">
<div class="container sample">
<div class="container fill">
<igc-grid id="grid" name="grid" height="480px" width="100%" autoGenerate='false'>
<igc-column field="ProductID"></igc-column>
<igc-column field="ProductName"></igc-column>
<igc-column field="UnitPrice" data-type="number"></igc-column>
<igc-column field="UnitsInStock" data-type="number" header-classes="headerAlignSyle">
<!-- <ng-template igcHeader>
<span class="cellAlignSyle">UnitsInStock</span>
</ng-template>
<ng-template igcCell let-val>
<div class="currency-badge-container">
<igc-badge *ngIf="val>50" type="success" position="bottom-right" icon="arrow_upward" class="badge-left"></igc-badge>
<igc-badge *ngIf="val<=50" type="error" position="bottom-right" icon="arrow_downward" class="error badge-left"></igc-badge>
<span class="cellAlignSyle" [class.up]="val>50" [class.down]="val<=50">{{ formatNumber(val) }}</span>
</div>
</ng-template> -->
</igc-column>
<igc-column field="QuantityPerUnit"></igc-column>
<igc-column field="ReorderLevel" data-type="number" header-classes="headerAlignSyle">
<!-- <ng-template igcHeader>
<span class="cellAlignSyle">ReorderLevel</span>
</ng-template>
<ng-template igcCell let-val>
<div class="currency-badge-container">
<igc-badge *ngIf="val>20" type="success" position="bottom-right" icon="arrow_upward" class="badge-left"></igc-badge>
<igc-badge *ngIf="val<=20" type="error" position="bottom-right" icon="arrow_downward" class="error badge-left"></igc-badge>
<span class="cellAlignSyle" [class.up]="val>0" [class.down]="val<=0">{{ formatNumber(val) }}</span>
</div>
</ng-template> -->
</igc-column>
</igc-grid>
</div>
</div>
</div>
<!-- This script is needed only for parcel and it will be excluded for webpack -->
<% if (false) { %><script src="src/index.ts"></script><% } %>
</body>
</html>
html/* shared styles are loaded from: */
/* https://static.infragistics.com/xplatform/css/samples */
css
Like this sample? Get access to our complete Ignite UI for Web Components toolkit and start building your own apps in minutes. Download it for free.
Remote Paging
The paging feature can operate with remote data. In order to demonstrate this let's first declare our service that will be responsible for data fetching. We will need the count of all data items in order to calculate the page count. This logic will be added to our service.
export class RemotePagingService {
public static CUSTOMERS_URL = `https://data-northwind.indigo.design/Customers/GetCustomersWithPage`;
constructor() {}
public static getDataWithPaging(pageIndex?: number, pageSize?: number) {
return fetch(RemotePagingService.buildUrl(RemotePagingService.CUSTOMERS_URL, pageIndex, pageSize))
.then((result) => result.json())
.catch((error) => console.error(error.message));
}
private static buildUrl(baseUrl: string, pageIndex?: number, pageSize?: number) {
let qS = "";
if (baseUrl) {
qS += `${baseUrl}`;
}
// Add pageIndex and size to the query string if they are defined
if (pageIndex !== undefined) {
qS += `?pageIndex=${pageIndex}`;
if (pageSize !== undefined) {
qS += `&size=${pageSize}`;
}
} else if (pageSize !== undefined) {
qS += `?perPage=${pageSize}`;
}
return `${qS}`;
}
}
ts
After declaring the service, we need to create a component, which will be responsible for the IgcGridComponent
construction and data subscription.
First we need to bind to the relevant events so when we change pages and the amount of records shown per page, the remote service will fetch the correct amount of data
constructor() {
this.grid = document.getElementById('grid') as IgcGridComponent;
this.pager = document.getElementById('paginator') as IgcPaginatorComponent;
this._bind = () => {
window.addEventListener("load", () => {
this.loadData(this.page,this.perPage);
});
this.pager.addEventListener("perPageChange", ((args: CustomEvent<any>) => {
this.perPage = args.detail;
this.loadData(this.page, this.perPage);
}) as EventListener);
this.pager.addEventListener("pageChange", ((args: CustomEvent<any>) => {
this.page = args.detail;
this.loadData(this.page, this.perPage);
}) as EventListener);
}
this._bind();
}
ts
We also need to set the method for loading data and update the UI accordingly:
private loadData(pageIndex?: number, pageSize?: number): void {
this.grid.isLoading = true;
RemotePagingService.getDataWithPaging(pageIndex,pageSize)
.then((response: CustomersWithPageResponseModel) => {
this.totalRecordsCount = response.totalRecordsCount;
this.pager.perPage = pageSize;
this.pager.totalRecords = this.totalRecordsCount;
this.page = response.pageNumber;
this.data = response.items;
this.grid.isLoading = false;
this.updateUI(); // Update the UI after receiving data
})
.catch((error) => {
console.error(error.message);
// Stop loading even if error occurs. Prevents endless loading
this.grid.isLoading = false;
this.updateUI();
})
}
private updateUI(): void {
if (this.grid && this.data) { // Check if grid and data are available
this.grid.data = this.data;
}
}
ts
For further reference, please check the demo bellow:
Grid Remote Paging Demo
import { BehaviorSubject, Observable, from } from 'rxjs';
import { map, catchError } from 'rxjs/operators';
export class RemotePagingService {
public remoteData: BehaviorSubject<any[]> = new BehaviorSubject([]);
public dataLength: BehaviorSubject<number> = new BehaviorSubject(0);
public url = 'https://www.igniteui.com/api/products';
constructor() {}
public async getData(index?: number, perPage?: number): Promise<any> {
let qS = '';
if (index !== undefined && perPage !== undefined) {
qS = `?$skip=${index}&$top=${perPage}&$count=true`;
}
try {
const response = await fetch(`${this.url + qS}`);
if (!response.ok) {
throw new Error('Network response was not ok');
}
const data = await response.json();
return data;
} catch (error) {
console.error('Error fetching data:', error);
throw error; // Propagate the error further
}
}
public async getDataLength(): Promise<number> {
try {
const response = await fetch(this.url);
if (!response.ok) {
throw new Error('Network response was not ok');
}
const data = await response.json();
return data.length; // Assuming the length is directly accessible in the JSON response
} catch (error) {
console.error('Error fetching data length:', error);
throw error; // Propagate the error further
}
}
}
tsimport 'igniteui-webcomponents-grids/grids/combined';
import { IgcGridComponent, IgcPaginatorComponent } from 'igniteui-webcomponents-grids/grids';
import "igniteui-webcomponents-grids/grids/themes/light/bootstrap.css";
import "./index.css";
import { RemotePagingService } from './RemotePagingService';
export class Sample {
public data: any[] = [];
public dataLength: number = 0;
private grid: IgcGridComponent;
private _bind: () => void;
private remotePagingService: RemotePagingService = new RemotePagingService();
public page = 0;
private _perPage = 10;
private pager: IgcPaginatorComponent;
public get perPage(): number {
return this.pager.perPage || 10;
}
private _totalRecordsCount: number;
public get totalRecordsCount(): number {
return this._totalRecordsCount;
}
public set totalRecordsCount(value: number) {
this._totalRecordsCount = value;
this.grid.totalRecords = value;
}
constructor() {
this.pager = document.getElementById('paginator') as IgcPaginatorComponent;
this.grid = document.getElementById('grid') as IgcGridComponent;
this._bind = () => {
this.remotePagingService.getDataLength().then((length) => {
this.totalRecordsCount = length;
this.pager.totalRecords = this.totalRecordsCount;
});
window.addEventListener("load", () => {
this.pager.totalRecords = this.totalRecordsCount;
this.paginate(0);
});
this.pager.addEventListener("perPageChange", ()=> {
this.paginate(0);
})
this.pager.addEventListener("pageChange", ((args: CustomEvent<any>) => {
this.paginate(args.detail);}) as EventListener);
}
this._bind();
}
public paginate(page: number) {
this.page = page;
const skip = this.page * this.perPage;
const top = this.perPage;
this.remotePagingService.getData(skip, top).then((data)=> {
this.data = data; // Assign received data to this.data
this.grid.isLoading = false;
this.updateUI(); // Update the UI after receiving data
});
}
public set perPage(val: number) {
this._perPage = val;
this.paginate(val);
}
private updateUI() {
if (this.grid && this.data) { // Check if grid and data are available
this.grid.data = this.data;
}
}
}
new Sample();
ts<!DOCTYPE html>
<html>
<head>
<title>Sample | Ignite UI | Web Components | infragistics</title>
<meta charset="UTF-8" />
<link rel="shortcut icon" href="https://static.infragistics.com/xplatform/images/browsers/wc.png" >
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Kanit&display=swap" />
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Titillium Web" />
<link rel="stylesheet" href="https://static.infragistics.com/xplatform/css/samples/shared.v8.css" />
<link rel="stylesheet" href="/src/index.css" type="text/css" />
</head>
<body>
<div id="root">
<div class="container sample ig-typography">
<div class="container fill">
<igc-grid
auto-generate="false"
name="grid"
id="grid"
moving="true"
paging-mode="Remote">
<igc-paginator
id="paginator">
</igc-paginator>
<igc-column
name="CategoryName"
id="CategoryName"
field="CategoryName"
header="Category Name">
</igc-column>
<igc-column
name="ImageID"
id="ImageID"
field="CategoryImageUrl"
data-type="image"
header="Category Image">
</igc-column>
<igc-column
name="ProductName"
id="ProductName"
field="ProductName"
header="Product Name">
</igc-column>
<igc-column
name="QuantityPerUnit"
id="QuantityPerUnit"
field="QuantityPerUnit"
header="Quantity Per Unit">
</igc-column>
<igc-column
name="UnitPrice"
id="UnitPrice"
field="UnitPrice"
header="Unit Price">
</igc-column>
<igc-column
name="SupplierName"
id="SupplierName"
field="SupplierName"
header="Supplier Name">
</igc-column>
<igc-column
name="UnitsInStock"
id="UnitsInStock"
field="UnitsInStock"
header="Units In Stock">
</igc-column>
<igc-column
name="UnitsOnOrder"
id="UnitsOnOrder"
field="UnitsOnOrder"
header="Units On Order">
</igc-column>
</igc-grid>
</div>
</div>
</div>
<!-- This script is needed only for parcel and it will be excluded for webpack -->
<% if (false) { %><script src="src/index.ts"></script><% } %>
</body>
</html>
html/* shared styles are loaded from: */
/* https://static.infragistics.com/xplatform/css/samples */
css
Known Issues and Limitations
- When the grid has no
PrimaryKey
set and remote data scenarios are enabled (when paging, sorting, filtering, scrolling trigger requests to a remote server to retrieve the data to be displayed in the grid), a row will lose the following state after a data request completes:
- Row Selection
- Row Expand/collapse
- Row Editing
- Row Pinning
API References
Additional Resources
- Paging
- Virtualization and Performance
- Filtering
- Sorting
- Summaries
- Column Moving
- Column Pinning
- Column Resizing
- Selection
Our community is active and always welcoming to new ideas.