The latest release of PnPjs contains 4 new methods. They allow you to copy and move, files and folders, to a different folder on the same or a different site collection. And they are incredibly fast!
Motivation
I have been recently asked by a client to develop a feature replacement to the default SharePoint copy and move to features. The OOB versions had some limitations that were causing problems to end users. With this in mind, I started by creating a proof-of-concept solution (SPFx list view command set extension). But soon realized that the functionality to copy and move files/folders between sites was not available in PnPjs. And so I added it and submitted a pull request (my first ever for the main PnPjs repository)!
Update: I wrote a blog post providing more details about the copy and move extension. You can read more here.
New copy and move features
- Copy and move documents and folders to the same site. PnPjs already had methods to do this, but using a different API endpoint
- Copy and move documents and folders to a different site
- If a file with the same name already exists, you can decide to replace or keep both. When keeping both files, a numeric value will by added to the name of the new file
- If a folder with the same name already exists when moving, you can decide to keep both. When keeping both folders, a numeric value will by added to the name of the new folder. The replace option is not available for folders
- Copying will not persist the version history of the source file
- Moving will persist the version history of the source file
Usage
As part of the pull request to add the new capabilities I have also updated the documentation (and tests) so people can easily understand how to use them. In short, your code will look similar to this (or use promises if you prefer):
Copy file by path
await sp.web.getFileByServerRelativePath(srcPath).copyByPath(`${destPath}/${name}`, shouldOverWrite, KeepBoth);
Move file by path
await sp.web.getFileByServerRelativePath(srcPath).moveByPath(`${destPath}/${name}`, shouldOverWrite, KeepBoth);
Copy folder by path
await sp.web.getFolderByServerRelativePath(srcPath).copyByPath(`${destPath}/${name}`, keepBoth);
Move folder by path
await sp.web.getFolderByServerRelativePath(srcPath).moveByPath(`${destPath}/${name}`, keepBoth);
Extra: Contributing to PnPjs
I use PnPjs for a very long time as it immensely helps me on my daily job, so I’m very happy that I was able to add a little bit more to it.
The project is so big that the first feeling I had was that adding the code there would take me longer than doing it on my own solution – but it clearly was the right thing to do. But guess what? The code is so well structured that this is actually pretty simple! All I had to do was to find the file where my functions should go (just follow the logical structure of folders that mirror the different packages) and find a similar function that I used as a starting point. Update the reference to the target REST API endpoint, update the data passed in the body (for POST requests) and all was done! All that was left to do after that was to update the documentation and tests, where I followed a similar approach.
We can all use it on any project going forward without having to worry about it! Sharing is caring 🙂
Hi, when I try to use .copyByPath() I get this System.UriFormatException “Invalid URI: The format of the URI could not be determined.”.
I tried it with both absolute and relative urls. On one and on two different site collections. Getting the File with .getFileByServerRelativePath() seems to be working.
Any idea how I can fix this? Thanks!
Hi Moritz, any chance you can share a sample request? Please don’t include sensitive information
You can also check the request url on the network tab of the browser dev tools and validate if the destination path is correct and a file name is provided. For example: /sites/mysite/mylibrary/testfile.pdf
Does it work for document sets? I tried it and it got copied as Folder sometimes ( when document set is not modified single time).
I really don’t know as I have not tested this scenario
Hi Joel
I hope you are doing fine.
I am having an error when using the .copyByPath
“{“odata.error”:{“code”:”-2147024809, System.ArgumentException”,”message”:{“lang”:”sv-SE”,”value”:”Value does not fall within the expected range.”}}}”.
I dont get it which value is it.
is the destination url or the source url. I am using ServerRelative urls and @pnp version is 2.0.9. When i use copyTo function it works fine but now i need to copy docs across a different site collection.
sp.web.getFileByServerRelativePath(surl).copyByPath(durl,true,false);
Can u please help me?
Hi Safwan,
Server relative URLs should be fine. If I am not wrong, it actually works with both.
I don’t remember having seen that exact error, but just checked the PnP repository and there is a recent issue related to dependency on odata.id. Can you give that a try on the setup method?
https://github.com/pnp/pnpjs/issues/1395#issuecomment-702743642
Nice article. One quick question.. I am using copy folder by path. When folder already exists it is creating a new folder with numerical value append. Can we append numerical value like _1, _2 so on?
Hi Sankar, you should be able to accomplish this using the last function parameter ‘keepBoth’. If you set it to true, it will automatically add the number at the end as you described, but if you set it to false, the request should fail as the folder already exists. You can then catch and handle this specific error so that it reties the request using a different folder name defined by you
Hi, do you know if there is a file size limit when moving files between site collections?
This works ok between libraries within the same site but between site collections for files around 50mb upwards I get this error:
{“odata.error”:{“code”:”-1, System.InvalidOperationException”,”message”:{“lang”:”en-US”,”value”:”File size over limit.”}}}
Many thanks
Hi, sorry for the late reply, had an issue with comments…
I believe there is a file limit of 50 Mb
Hello Great article i have the copy function working is it possible to add extra metadata for other column in the destination doc lib which is a list column in my case?
Sorry for the late reply…
I assume you have resolved this, but for future reference, yes it is possible, but you have to execute an update after moving, it can’t be done as part of the same request
Hi , i have a problem . I use your code , but I saw this error :
sp.web.getFolderByServerRelativePath(…).copyByPath is not a function
Hi, sorry for the late reply.
I assume the issue is now resolved, but I guess it must have been caused for some missing import. PnPjs documentation is probably the best reference here
https://pnp.github.io/pnpjs/sp/files/#copy-by-path