/** * This code example shown how you can create a list item in another list in the site collection after saving a list item in the current list. * Add the below code in Custom JS in your NewForm or EditForm and modify the dffs_PostSaveAction function to write the desired data to the other list. * All other fuctions in this example are helper function that do not need changing. */ function showError(title, body) { dffs_showModal({ "title": title, "body": body, "ok": () => { // Close dialog } }); } /** * Fetches the ListItemEntityTypeFullName for a given list using Fetch API. * This is required in the '__metadata' property when creating an item. * @param {string} siteUrl - The absolute URL of the SharePoint site. * @param {string} listTitle - The title of the SharePoint list. * @returns {Promise} A promise that resolves with the ListItemEntityTypeFullName string. */ async function getListItemEntityTypeFullName(siteUrl, listTitle) { const endpointUrl = `${siteUrl}/_api/web/lists/getbytitle('${listTitle}')?$select=ListItemEntityTypeFullName`; const headers = { "Accept": "application/json;odata=verbose" }; try { const response = await fetch(endpointUrl, { method: "GET", headers: headers }); if (!response.ok) { const errorData = await response.json().catch(() => ({})); // Try to get error details throw new Error(`HTTP error ${response.status} while fetching ListItemEntityTypeFullName. Details: ${JSON.stringify(errorData)}`); } const data = await response.json(); if (data.d && data.d.ListItemEntityTypeFullName) { return data.d.ListItemEntityTypeFullName; } else { throw new Error("ListItemEntityTypeFullName not found in response."); } } catch (error) { showError("Error in getListItemEntityTypeFullName:", error); throw error; // Re-throw the error to be caught by the caller } } /** * Fetches the Request Digest value from SharePoint using Fetch API. * This is required for any POST/PUT/DELETE operations. * @param {string} siteUrl - The absolute URL of the SharePoint site. * @returns {Promise} A promise that resolves with the FormDigestValue string. */ async function getRequestDigest(siteUrl) { const endpointUrl = `${siteUrl}/_api/contextinfo`; const headers = { "Accept": "application/json;odata=verbose" }; try { const response = await fetch(endpointUrl, { method: "POST", // contextinfo requires POST headers: headers }); if (!response.ok) { const errorData = await response.json().catch(() => ({})); throw new Error(`HTTP error ${response.status} while fetching Request Digest. Details: ${JSON.stringify(errorData)}`); } const data = await response.json(); if (data.d && data.d.GetContextWebInformation && data.d.GetContextWebInformation.FormDigestValue) { return data.d.GetContextWebInformation.FormDigestValue; } else { throw new Error("FormDigestValue not found in contextinfo response."); } } catch (error) { showError("Error in getRequestDigest:", error); throw error; } } /** * Resolves a user's login name to their SharePoint User ID. * @param {string} siteUrl - The absolute URL of the SharePoint site. * @param {string} loginName - The login name of the user e.g., 'i:0#.f|membership|user@tenant.onmicrosoft.com'. * @returns {Promise} A promise that resolves with the SharePoint User ID. */ async function resolveUserLoginToId(siteUrl, loginName) { const endpointUrl = `${siteUrl}/_api/web/siteusers?$filter=LoginName eq '${encodeURIComponent(loginName)}'&$select=Id`; const headers = { "Accept": "application/json;odata=verbose" }; try { const response = await fetch(endpointUrl, { method: "GET", headers: headers }); if (!response.ok) { const errorData = await response.json().catch(() => ({})); throw new Error(`HTTP error ${response.status} while resolving user login to ID. Details: ${JSON.stringify(errorData)}`); } const data = await response.json(); if (data.d && data.d.results && data.d.results.length > 0) { return data.d.results[0].Id; } else { throw new Error(`User with login name '${loginName}' not found.`); } } catch (error) { showError(`Error in resolveUserLoginToId for '${loginName}':`, error); throw error; } } /** * Creates a new item in a SharePoint list using Fetch API. * @param {string} siteUrl - The absolute URL of the SharePoint site. * @param {string} listTitle - The title of the SharePoint list. * @param {object} itemProperties - An object containing the properties (fields and values) for the new item. * @returns {Promise} A promise that resolves with the data of the newly created item. */ async function createSharePointListItem(siteUrl, listTitle, itemProperties) { try { const requestDigest = await getRequestDigest(siteUrl); const endpointUrl = `${siteUrl}/_api/web/lists/getbytitle('${listTitle}')/items`; // Ensure the itemProperties object has the correct __metadata type console.log("Fetching ListItemEntityTypeFullName..."); const listItemEntityTypeFullName = await getListItemEntityTypeFullName(siteUrl, listTitle); console.log("List Item Entity Type Full Name:", listItemEntityTypeFullName); const payload = { ...itemProperties, // Spread existing properties '__metadata': { 'type': listItemEntityTypeFullName } }; const headers = { "Accept": "application/json;odata=verbose", "Content-Type": "application/json;odata=verbose", "X-RequestDigest": requestDigest }; const response = await fetch(endpointUrl, { method: "POST", headers: headers, body: JSON.stringify(payload) }); if (!response.ok) { // Attempt to parse error response from SharePoint, which might not always be JSON let errorDetails = `HTTP error ${response.status}`; try { const errorData = await response.json(); errorDetails += ` - ${errorData?.error?.message?.value || JSON.stringify(errorData)}`; } catch (e) { // If parsing as JSON fails, try to get text const errorText = await response.text(); errorDetails += ` - ${errorText}`; } throw new Error(errorDetails); } return await response.json(); // Return the created item data } catch (error) { showError("Error in createSharePointListItem:", error.message); throw error; } } /** * The function dffs_PostSaveAction will run after the list item has been saved. This means that you have access to the item ID and can write it to the other list. * The newItemPayload object maps the values from the current item to a data objec that will be written to the other list. You must use internal name of the fields both in * the current list (in the getFieldValue function) and in the other list in the key in the data object. * Please note that you must not pass in values to the newItemPayload for empty fields. This is not handled in the below code example */ async function dffs_PostSaveAction() { const getQueryParam = (name) => { const urlParams = new URLSearchParams(window.location.search); return urlParams.get(name); } // Add any condtions for creating the child list item, or redirect out of the current form using something like this: /** if (getFieldValue("Status") !== "Completed") { // Don't trigger the creation // Redirect to the address in the Source attribute of the URL search string location.href = getQueryParam("Source"); return; } // If you got past the previous conditional check, go ahead and create the child list item */ const childListTitle = "List_B"; const childListSiteUrl = _spPageContextInfo.webAbsoluteUrl; const newItemPayload = { // --- Write current item ID to a text field named ParentItemID in the other list --- 'ParentItemID': getFieldValue("ID"), // --- Text Field --- 'Title': getFieldValue("Title"), // Assuming 'Title' is your text field // --- Multiple Lines of Text Field --- 'MultilineTextField': getFieldValue("MultilineTextField"), // --- Number Field --- 'NumberField': Number(getFieldValue("NumberField")), // --- Single choice Field --- 'SingleChoice': getFieldValue("SingleChoice"), // --- Multi choice Field --- 'MultiChoice': { results: getFieldValue("MultiChoice") }, // --- Date/Time Field --- 'DateField': getFieldValue("DateField", "object").toISOString(), // --- Person or Group Field (Single User) --- // Replace 'PeoplePickerId' with your field's internal name + "Id" // The value must be the SharePoint User ID (integer). // Example: If your Person field internal name is "ProjectLead", use "ProjectLeadId". 'PeoplePickerId': await resolveUserLoginToId(_spPageContextInfo.webAbsoluteUrl, getFieldValue("PeoplePicker")[0].loginName) // For a multi-user Person field: // 'MultiUserFieldInternalNameId': { 'results': [12, 15] } }; try { console.log("Payload to be sent:", newItemPayload); console.log("Creating list item..."); const createdItemData = await createSharePointListItem(childListSiteUrl, childListTitle, newItemPayload); console.log("Item created successfully!", createdItemData); if (createdItemData.d) { console.log("Created Item ID:", createdItemData.d.Id); // Redirect to the address in the Source attribute of the URL search string location.href = getQueryParam("Source"); } } catch (error) { showError("Operation failed:", error.message); // Provide user-friendly error feedback here in a real application // You must also handle the redirect back to the list or to an error-page with more information } }