Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[data grid] Is there any way to copy paste programmatically? #15114

Open
Tracked by #9328
KaralyosBela opened this issue Oct 25, 2024 · 5 comments
Open
Tracked by #9328

[data grid] Is there any way to copy paste programmatically? #15114

KaralyosBela opened this issue Oct 25, 2024 · 5 comments
Labels
component: data grid This is the name of the generic UI component, not the React module! feature: Clipboard Related to clipboard copy or paste functionalities recipe support: commercial Support request from paid users support: premium standard Support request from a Premium standard plan user. https://mui.com/legal/technical-support-sla/ support: question Community support but can be turned into an improvement

Comments

@KaralyosBela
Copy link

KaralyosBela commented Oct 25, 2024

The problem in depth

Hey!

We are using the copy paste very often in our app.

A question has arisen as to whether it would be possible to copy paste at the press of a button. Pressing the copy button would save the values just like pressing ctrl + c. Then pressing the paste button would create as many lines as were copied and paste the copied values. Is it possible to do this or is it currently not possible in datagrid?

I tried selecting a few lines, ctrl + c, then ctrl + v and then using the onClipboardPasteStart function to create as many lines as I copied, but then I have to update the selectionModel to make the paste available, but I got stuck.

Your environment

`npx @mui/envinfo`
  Don't forget to mention which browser you used.
    System:
    OS: Windows 10 10.0.19045
  Binaries:
    Node: 22.5.1 - C:\Program Files\nodejs\node.EXE
    npm: 10.8.2 - C:\Program Files\nodejs\npm.CMD
    pnpm: 9.6.0 - ~\AppData\Local\pnpm\pnpm.EXE
  Browsers:
    Chrome
  npmPackages:
    @emotion/react: ^11.13.3 => 11.13.3
    @emotion/styled: ^11.13.0 => 11.13.0
    @mui/base: ^5.0.0-beta.26 => 5.0.0-beta.35
    @mui/icons-material: ^5.16.7 => 5.16.7
    @mui/lab: 5.0.0-alpha.141 => 5.0.0-alpha.141
    @mui/material: ^5.16.7 => 5.16.7
    @mui/x-data-grid-premium: ^7.20.0 => 7.20.0
    @mui/x-date-pickers:  7.21.0
    @mui/x-license: ^7.20.0 => 7.20.0
    @mui/x-tree-view-pro: ^7.20.0 => 7.20.0
    @types/react: 18.2.33 => 18.2.33
    react: 18.2.0 => 18.2.0
    react-dom: 18.2.0 => 18.2.0
    styled-components: 5.3.6 => 5.3.6
    typescript: ~5.2.2 => 5.2.2

Search keywords: Copy paste
Order ID: 86461

@KaralyosBela KaralyosBela added status: waiting for maintainer These issues haven't been looked at yet by a maintainer support: commercial Support request from paid users labels Oct 25, 2024
@github-actions github-actions bot added component: data grid This is the name of the generic UI component, not the React module! support: premium standard Support request from a Premium standard plan user. https://mui.com/legal/technical-support-sla/ labels Oct 25, 2024
@KenanYusuf KenanYusuf changed the title Is there any way to copy paste programmatically in datagrid? [data grid] Is there any way to copy paste programmatically? Oct 25, 2024
@KenanYusuf KenanYusuf added support: question Community support but can be turned into an improvement feature: Clipboard Related to clipboard copy or paste functionalities labels Oct 25, 2024
@michelengelen
Copy link
Member

michelengelen commented Oct 28, 2024

Hey @KaralyosBela ... this might be possible when using the paste operation events.
There is the onBeforeClipboardPasteStart prop you can use to determine the number of rows you have in your clipboard:

import * as React from 'react';
import { DataGridPremium, DataGridPremiumProps, useGridApiRef } from '@mui/x-data-grid-premium';
import { randomEmail, randomId, randomUserName } from '@mui/x-data-grid-generator';

const columns = [
  {
    field: 'name',
    headerName: 'Name',
    width: 250,
    editable: true,
  },
  {
    field: 'email',
    headerName: 'Email',
    width: 350,
    editable: true,
  },
];

const generateRandomRows = (count: number) => {
  const rows = [];
  for (let i = 0; i < count; i += 1) {
    rows.push({
      id: randomId(),
      name: randomUserName(),
      email: randomEmail(),
    });
  }
  return rows;
};

const initialRows = generateRandomRows(100);

console.log(initialRows);

const parseDataIntoRows = (data: string[][]) => {
  return data.map((row) => {
    const [name, email] = row;
    return { id: randomId(), name, email };
  });
};

export default function ClipboardPaste() {
  const apiRef = useGridApiRef();

  const handleBeforeClipboardPaste: DataGridPremiumProps['onBeforeClipboardPasteStart'] = ({
    data,
  }) => {
    console.log(data.length);
    if (data.length === 0) {
      console.log('no data to paste');
      return Promise.reject();
    }
    // you need to have a function that will take the data from the clipboard and create a row object
    const newRows = parseDataIntoRows(data);
    apiRef.current.updateRows(newRows);
    // we need to reject, because otherwise we will also override the selected rows with the values in the clipboard
    return Promise.reject();
  };

  return (
    <div style={{ height: 500, width: '100%' }}>
      <DataGridPremium
        rows={initialRows}
        columns={columns}
        apiRef={apiRef}
        ignoreValueFormatterDuringExport
        onBeforeClipboardPasteStart={handleBeforeClipboardPaste}
      />
    </div>
  );
}

Demo in Codesandbox

This way you will be able to add new rows instead

@michelengelen michelengelen added status: waiting for author Issue with insufficient information and removed status: waiting for maintainer These issues haven't been looked at yet by a maintainer labels Oct 28, 2024
@KaralyosBela
Copy link
Author

Thanks for your solution, it works. The only problem with this, that if we want to use the default copy paste with the checkboxes to copy paste entire rows, or copy paste one or multiple cells, then this new solution applies only. So my question is: is there any way that we can use this new solution of yours with a button, for example: check 3 rows, press a button -> adds 3 rows with the copied data, and if we don't use the button, use the default copy paste.

@github-actions github-actions bot added status: waiting for maintainer These issues haven't been looked at yet by a maintainer and removed status: waiting for author Issue with insufficient information labels Oct 29, 2024
@KaralyosBela
Copy link
Author

After thinking a bit, this could be achieved by watching the row selection model, and get the values with the apiRef.current.getSelectedRows(), then add that many rows with the values. This way we do not need to change the copy paste.

@michelengelen
Copy link
Member

@KaralyosBela that's even easier. Look at that example:

import * as React from 'react';
import { DataGridPremium, useGridApiRef } from '@mui/x-data-grid-premium';
import { randomEmail, randomId, randomUserName } from '@mui/x-data-grid-generator';
import { Button, Stack } from '@mui/material';

const columns = [
  {
    field: 'name',
    headerName: 'Name',
    width: 250,
    editable: true,
  },
  {
    field: 'email',
    headerName: 'Email',
    width: 350,
    editable: true,
  },
];

const generateRandomRows = (count: number) => {
  const rows = [];
  for (let i = 0; i < count; i += 1) {
    rows.push({
      id: randomId(),
      name: randomUserName(),
      email: randomEmail(),
    });
  }
  return rows;
};

const initialRows = generateRandomRows(5);

const parseTextToData = (text: string) => {
  return text.split('\n').map((row) => row.split('\t'));
};

const parseDataIntoRows = (data: string[][]) => {
  return data.map((row) => {
    const [name, email] = row;
    return { id: randomId(), name, email };
  });
};

export default function ClipboardPaste() {
  const apiRef = useGridApiRef();
  const [clipboardData, setClipboardData] = React.useState<string[][]>([]);

  const handleClipboardCopy = (text: string) => {
    const data = parseTextToData(text);
    setClipboardData(data);
  };

  const handleAddClipboardTextAsRows = () => {
    const newRows = parseDataIntoRows(clipboardData);
    apiRef.current.updateRows(newRows);
  };

  return (
    <div style={{ height: 500, width: '100%' }}>
      <Stack direction="row" gap={1} mb={1} flexWrap="wrap">
        <Button
          onClick={handleAddClipboardTextAsRows}
          variant="outlined"
          disabled={!clipboardData.length}
        >
          {!!clipboardData.length ? `Add ${clipboardData.length} rows` : 'No data to paste'}
        </Button>
      </Stack>
      <DataGridPremium
        rows={initialRows}
        columns={columns}
        apiRef={apiRef}
        ignoreValueFormatterDuringExport
        onClipboardCopy={handleClipboardCopy}
      />
    </div>
  );
}

@mui/xgrid should we maybe add this example as a recipe?

@michelengelen michelengelen added status: waiting for author Issue with insufficient information and removed status: waiting for maintainer These issues haven't been looked at yet by a maintainer labels Oct 30, 2024
@KaralyosBela
Copy link
Author

Thanks, this way I managed to do what I wanted!

@github-actions github-actions bot added status: waiting for maintainer These issues haven't been looked at yet by a maintainer and removed status: waiting for author Issue with insufficient information labels Oct 31, 2024
@github-project-automation github-project-automation bot moved this to 🆕 Needs refinement in MUI X Data Grid Nov 4, 2024
@michelengelen michelengelen added recipe and removed status: waiting for maintainer These issues haven't been looked at yet by a maintainer labels Nov 4, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
component: data grid This is the name of the generic UI component, not the React module! feature: Clipboard Related to clipboard copy or paste functionalities recipe support: commercial Support request from paid users support: premium standard Support request from a Premium standard plan user. https://mui.com/legal/technical-support-sla/ support: question Community support but can be turned into an improvement
Projects
Status: 🆕 Needs refinement
Development

No branches or pull requests

3 participants