How to add custom button to toolbar of List or Library control and duplicate selected item

In this scenario, we’ll show you how to add button to List or Library control, which would duplicate currently selected item.

Duplicate button

Note

For more samples of how you can customize this control’s buttons, check out List or Library buttons article.

Form configuration

Create a form with a List or Library control. Then, check Internal Names of the fields in List or Library source list - you need to know these, so you can copy them.

You can open Child List form in the editor and check Internal Names there. For example, my Child item has the following fields to copy: “Title” (Single line), “Description” (Plain text), “Price” (Currency), “Supervisor” (Person), and “Parent” (Lookup).

Internal Names

I can check Internal Name for each field, and make sure that I have correct one.

Then, on the Parent Form, I will add the following code:

//Use Internal Names of your fields
const fieldsToCopy = ['Title', 'Description', 'Price', 'Supervisor', 'Parent'];

async function copySelectedItems(selectedItems, items) {
    return await Promise.all(
        selectedItems.map(async (selected) => {
            const item = await items.getById(selected.ID).get();

            const copy = {};

            //go through fields and copy each one
            fieldsToCopy.forEach((field) => {
                //copy regular fields
                if (item[field]) {
                    copy[field] = item[field];
                }
                //copy more complex fields - Person/Lookup
                else if (item[field + 'Id']) {
                    copy[field + 'Id'] = item[field + 'Id'];
                }
            });

            return copy;
        })
    );
}

fd.spRendered(() => {
    const lol = fd.control('Control1');

    //new button
    var duplicateButton = {
        text: 'Duplicate item',
        class: 'btn-secondary',
        visible: false,
        icon: 'Copy',
        iconType: 0,
        click: async () => {
            const listUrl = lol.listRootFolder;
            const selected = lol.selectedItems;
            const items = pnp.sp.web.getList(listUrl).items;
            const copies = await copySelectedItems(selected, items);
            console.log(copies);

            const batch = pnp.sp.web.createBatch();
            const batchItems = items.inBatch(batch);

            copies.forEach((copy) => {
                batchItems.add(copy).catch(console.warn);
            });

            await batch.execute();

            lol.refresh();
            duplicateButton.visible = false;
        },
    };

    lol.ready((dt) => {
        dt.buttons.push(duplicateButton);

        dt.$watch('selectedItems', items => {
            duplicateButton.visible = items?.length;
        });
    });
});

Now, this would allow me to select and copy any number of items in List or Library, and it will work in both Dialog and Inline editing mode.

Several duplicates