Enhancing SharePoint List Fetching: Additional Fields, Filters, and Pagination

Retrieving SharePoint list items is essential in many SPFx solutions. However, in real-world scenarios, you may need to:

  • Include additional fields: Fetch more columns from the list beyond the default ones.
  • Apply filters: Retrieve only specific items based on conditions.
  • Handle pagination: Fetch large lists efficiently without hitting API limits.

Code Enhancement

The updated function allows:
✅ Specifying additional fields using $select
✅ Applying filters with $filter
✅ Handling pagination using @odata.nextLink

import { HttpClient, HttpClientResponse } from '@microsoft/sp-http';

/**
 * Fetches SharePoint list items with optional fields, filters, and pagination.
 *
 * @param {any} context - The SharePoint context for API calls.
 * @param {string} listTitle - The SharePoint list title.
 * @param {string[]} additionalFields - List of extra fields to retrieve.
 * @param {string} filter - OData filter string (optional).
 * @returns {Promise<any[]>} - Returns a structured array of list items.
 */
export async function FetchListItemsExtended(
    context: any,
    listTitle: string,
    additionalFields: string[] = [],
    filter: string = ""
): Promise<any[]> {
    try {
        const siteUrl = context.pageContext.web.absoluteUrl;
        const selectFields = ["Id", "Title", "Created", "Modified", ...additionalFields].join(",");
        let apiUrl = `${siteUrl}/_api/web/lists/getbytitle('${listTitle}')/items?$select=${selectFields}`;

        if (filter) {
            apiUrl += `&$filter=${encodeURIComponent(filter)}`;
        }

        console.log("Fetching API URL:", apiUrl);

        let allItems: any[] = [];
        let nextUrl: string | null = apiUrl;

        // Handle pagination by iterating through nextLink responses
        while (nextUrl) {
            const response: HttpClientResponse = await context.httpClient.get(nextUrl, HttpClient.configurations.v1, {
                headers: {
                    'Accept': 'application/json;odata=nometadata',
                    'Content-Type': 'application/json;odata=nometadata'
                }
            });

            console.log("Response Status:", response.status);
            if (!response.ok) {
                throw new Error(`Failed to fetch list items: ${response.statusText}`);
            }

            const data = await response.json();
            console.log("Raw Data:", data);

            allItems = [...allItems, ...data.value];

            // Check for pagination
            nextUrl = data["@odata.nextLink"] || null;
        }

        // Transform the list items into a structured object
        const items = allItems.map((item: any) => ({
            id: item.Id,
            title: item.Title,
            created: item.Created,
            modified: item.Modified,
            ...additionalFields.reduce((obj, field) => ({ ...obj, [field]: item[field] || null }), {})
        }));

        console.log("Processed Items:", items);
        return items;
    } catch (error) {
        console.error("Error fetching list items:", error);
        return [];
    }
}

Example Usage

1️⃣ Fetching Items with Additional Fields

const listItems = await FetchListItemsExtended(context, "Documents", ["Author", "Category"]);
console.log(listItems);

2️⃣ Filtering Items (e.g., only documents created in 2024)

const filter = "Created ge datetime'2024-01-01T00:00:00Z'";
const filteredItems = await FetchListItemsExtended(context, "Documents", ["Author"], filter);
console.log(filteredItems);

3️⃣ Fetching Large Lists with Pagination

The function automatically handles large lists using @odata.nextLink, ensuring that all items are retrieved efficiently.

Conclusion

This enhanced function provides:
✔️ Flexibility – Fetch any fields you need
✔️ Filtering – Retrieve only relevant data
✔️ Performance Optimization – Efficiently handle large lists

With this approach, your SPFx solutions can be more scalable and efficient.

Edvaldo Guimrães Filho Avatar

Published by

Categories: