Request new features or modifications


Post by vadim_g »

Hi guys,

currently in RowReorder, when dragging from left grid to right grid, there is no way to configure in code the RowReorder to clone (copy with the same id) the dropped records. For clone see viewtopic.php?p=173815#p173815

And is tricky to add an workaround for it. If somehow I manage to pass the isCopy as true in finalizeReorder(context, isCopy), then it will copy not clone the record.

Thanks.
Vadim

Last edited by vadim_g on Mon Sep 15, 2025 11:48 am, edited 1 time in total.

Post by tasnim »

Hi Vadim,

You can do this today using the RowReorder.allowCrossGridDrag option and provide a custom transferData implementation that copies the records instead of moving them. Example:

const grid = new Grid({
  features : {
    rowReorder : {
      allowCrossGridDrag : {
        async transferData({ records, insertBefore, parent, target }) {
          // create copies
          const copies = records.map(r => r.copy());
          // insert into target store / tree (use parent.insertChild for tree stores)
          if (parent) {
            await parent.insertChild(copies, insertBefore);
          } else {
            await target.store.insert(copies, insertBefore?.index ?? target.store.count);
          }
        }
      }
    }
  }
});

Note: copy() gives new records with new ids. If you really must keep the same id, you can set id explicitly on the copy, but be careful — duplicate ids in a Store can cause issues. Don’t rely on internal finalizeReorder hacks; transferData is the supported way. See RowReorder.allowCrossGridDrag for details.

Best regards,
Tasnim

How to ask for help? Please read our Support Policy


Post by vadim_g »

So if I have many places where I need this, would mean I need to extend RowReorder into a new class to add this capability through a config, just to avoid current behaviour ? Hmm ok :(


Post by tasnim »

Hi Vadim,

You don't need to subclass RowReorder, create a small reusable transferData function and reuse it in each grid's feature config. Example:

const makeCopyTransfer = (keepId = false) => async ({ records, insertBefore, parent, target }) => {
  const copies = records.map(r => {
    const c = r.copy();
    if (keepId) c.id = r.id; // WARNING: duplicate ids can break the store
    return c;
  });

  if (parent) {
    await parent.insertChild(copies, insertBefore);
  } else {
    await target.store.insert(copies, insertBefore?.index ?? target.store.count);
  }
};

// then reuse in grids
features : {
  rowReorder : {
    allowCrossGridDrag : {
      transferData : makeCopyTransfer(/*keepId=*/ false)
    }
  }
}

This avoids changing internal finalizeReorder and uses the supported RowReorder.allowCrossGridDrag API. If you must preserve ids be careful about duplicate id issues.

Best regards,
Tasnim

How to ask for help? Please read our Support Policy


Post by vadim_g »

But still, I don't think what you proposed it is a good idea (it's fine only as a temporary workaround), especially that I have to handle myself the Insert part - which is overhead and duplicated code, that we need to maintain and test (component tests) ourselves, considering that the Reorder feature does that already. We just need a simple config to instruct to clone/copy the records and not move...


Post by vadim_g »

Your code is wrong, according to RowReorder the insert is like this:

	const { store } = targetGrid;

					const index = insertBefore
						? store.indexOf(insertBefore)
						: store.count;

					await store.insert(index, copies);

and not:

// there is no index in insertBefore, and the args are reversed.
target.store.insert(copies, insertBefore?.index ?? target.store.count);

unless you are using a different B version ?

Surely is way less code to extend Reorder class and define in tens of places only this:

features: {
     myRowReorder: true
},

instead of this:

  rowReorder : {
    allowCrossGridDrag : {
      transferData : makeCopyTransfer(/*keepId=*/ false)
    }
  }

So still, in our opinion just a simple config in Rowreorder would be way better, so we don't handle that insert part ourselves since is there in finalizeReorder.

Thanks.
Vadim


Post by joakim.l »

Hi

You are right, there are no index field on Model.
And, a record can also belong to multiple Stores. Maybe that is what you seek by using the same id?

A valid approach should be something like this:

features : {
    rowReorder : {
         allowCrossGridDrag : {
             transferData({ records, insertBefore, targetGrid }) {
                 targetGrid.store.insert(targetGrid.store.indexOf(insertBefore), records);    
} } } }

The transferData is there exactly for these kinds of cases where the imlementation needs something other than the default behaviour.

If you want to subclass the RowReorder feature, or implement it as a config, thats up to you.
Here are some details on making a new feature: https://bryntum.com/products/grid/docs/api/Grid/feature/GridFeatureManager

Regards
Joakim


Post by vadim_g »

Hi Joakim,

Yes, we extended it already, ok, understood, thank your for jumping in though.

We are aware of the records and store inner workings. We just have a DualGridDialog kind of combo picker, where the user selects rows from the left grid, so the id must be kept as well as it's eventually sent to Backend, so 2 grids with 2 stores sharing the same data through cloning.

Vadim


Post Reply