How to create folder with custom Content Type in REST with SPFx?
-
25-01-2021 - |
Pregunta
I am creating an SPFx solution to create folders with nested folders. This solution is working fine. but I want to attach some metadata to my folder. For this reason I have created a new folder content type and added few site columns to it. But I am not getting how to update the content type value while creating the folder. I am using below code for folder creation
private createFolder(folderUrl: string): Promise<any> {
let customFolderCTId = "0x012000F1CF7BFF04CE7344891D1F19E91A18ED";
const spOpts: ISPHttpClientOptions = {
body: JSON.stringify({
'ContentTypeId':customFolderCTId
})
};
return (
this.state.context.spHttpClient.post(folderUrl,SPHttpClient.configurations.v1,spOpts).then((r: SPHttpClientResponse) => {
return r.json()
}) as Promise<any>
);
}
Above code is giving me error as {"error":{"code":"-1, Microsoft.SharePoint.Client.InvalidClientQueryException","message":"The parameter ContentTypeId does not exist in method Add."}}
What is the resolution for this?
Solución
You need to modify your existing endpoint include the details of the created folder by including select and expand OData operator as below:
"/_api/web/folders/add('${libraryName}/${clientName}')?
$select=ListItemAllFields/*&$expand=ListItemAllFields"
Once you do this, you can get the ID of the created folder item. After that, its a simple update operation to the list item.
The code will be somewhat as below:
let _folderUrl = this.context.pageContext.web.absoluteUrl +
"/_api/web/folders/add(`${libraryName}/${clientName}`)?
$select=ListItemAllFields/*&$expand=ListItemAllFields";
const body: string = JSON.stringify({});
this.context.spHttpClient.post(_folderUrl,
SPHttpClient.configurations.v1,
{
body: body
}).then((response): Promise<void> => {
return response.json();
})
.then((item): void => {
console.log(item);
// get the created folder item Id
var itemId = item["ListItemAllFields"]["ID"];
var folderItemUrl = this.context.pageContext.web.absoluteUrl +
"/_api/web/lists/getByTitle(`${libraryName}`)/items('" + itemId +"')";
// use the list item entity type full name
const updateBody: string = JSON.stringify({
"__metadata": {"type":"SP.Data.`${libraryName}`Item"},
"ContentTypeId":"0x012000F1CF7BFF04CE7344891D1F19E91A18ED"
});
this.context.spHttpClient.post(folderItemUrl,SPHttpClient.configurations.v1,{
headers: {
'Accept': 'application/json;odata=verbose',
'Content-type': 'application/json;odata=verbose',
'odata-version': '',
'IF-MATCH': '*',
'X-HTTP-Method': 'MERGE'
},
body:updateBody
}).then(d =>{
console.log("success updating folder content type");
});
}, (error: any): void => {
console.log(error);
});
Otros consejos
The accepted answer here was tremendously helpful, but there are a lot of areas for improvement: it makes assumptions about the folder path and the type value (the one that starts with "SP.Data"), it fails to escape the values it inserts into the URLs, and it has a broken chain.
I've improved on these areas and also cleaned up the code a bit to break it down into more consumable chunks.
Disclaimer: I don't have an easy way to test this code, so it may contain some small mistakes. Please feel free to propose an edit if you find any.
const jsonOdataVerbose = 'application/json;odata=verbose';
const escapeParam = (value) => encodeURIComponent(value.replace(/'/g, "''"));
const listByTitle = (webUrl, listName) =>
`${webUrl}/_api/web/lists/getbytitle('${escapeParam(listName)}')`;
function createFolder(context, library, folderName) {
const webUrl = context.pageContext.web.absoluteUrl;
const requestUrl =
`${listByTitle(webUrl, library)}/rootfolder/folders/add('${escapeParam(folderName)}')` +
`?$select=ListItemAllFields/*&$expand=ListItemAllFields`;
return context.spHttpClient.post(
requestUrl,
SPHttpClient.configurations.v1,
{
headers: {
Accept: jsonOdataVerbose,
},
},
).then(response => response.json());
}
function setContentType(context, library, id, type, contentType) {
const webUrl = context.pageContext.web.absoluteUrl;
const requestUrl =
`${listByTitle(webUrl, library)}/items('${id}')`;
const payload = {
__metadata: { type },
ContentTypeId: contentType
};
return context.spHttpClient.post(
requestUrl,
SPHttpClient.configurations.v1,
{
body: JSON.stringify(payload),
headers: {
Accept: jsonOdataVerbose,
'Content-Type': jsonOdataVerbose,
'IF-MATCH': '*',
'X-HTTP-Method': 'MERGE',
},
},
);
}
// put it all together
createFolder(this.context, libraryName, clientName)
.then(item => setContentType(
this.context,
libraryName,
item['ListItemAllFields']['ID'],
item['ListItemAllFields']['__metadata']['type'],
'0x012000F1CF7BFF04CE7344891D1F19E91A18ED'
))
.catch(error => console.error(error));