Skip to content

Commit

Permalink
feat: add onBeforePasteCell event to excel copy buffer (#1298)
Browse files Browse the repository at this point in the history
* feat: add `onBeforePasteCell` event to excel copy buffer
  • Loading branch information
zewa666 authored Jan 4, 2024
1 parent 4b0d4c2 commit 22037ca
Show file tree
Hide file tree
Showing 11 changed files with 321 additions and 72 deletions.
1 change: 1 addition & 0 deletions docs/TOC.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
* [Custom Tooltip](grid-functionalities/custom-tooltip.md)
* [Context Menu](grid-functionalities/Context-Menu.md)
* [Custom Footer](grid-functionalities/Custom-Footer.md)
* [Excel Copy Buffer Plugin](grid-functionalities/excel-copy-buffer.md)
* [Export to Excel](grid-functionalities/Export-to-Excel.md)
* [Export to File (csv/txt)](grid-functionalities/Export-to-Text-File.md)
* [Grid Menu](grid-functionalities/Grid-Menu.md)
Expand Down
1 change: 1 addition & 0 deletions docs/events/Available-Events.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ handleOnHeaderMenuCommand(e) {
- `onCopyCells`
- `onCopyCancelled`
- `onPasteCells`
- `onBeforePasteCell`

#### SlickContextMenu (extension)
- `onContextMenuClearGrouping`
Expand Down
129 changes: 129 additions & 0 deletions docs/grid-functionalities/excel-copy-buffer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
### Description
Just like Excel you can select multiple cell and copy (`Ctrl+C`) and paste to Excel (`Ctrl+V`). However what you must know is that this plugin evaluate every single cell by their values (the raw value unless you specify otherwise, continue reading for more info).

### Usage
All you need to do is enable the Grid Option `enableExcelCopyBuffer: true` and give it a try. From your grid, start selecting multiple cells with the mouse then copy (with `Ctrl+C`) and paste to Excel (with `Ctrl+V`)

##### Component
```typescript
this.columnDefinitions = [
{ id: 'title', name: 'Title', field: 'id' },
{ id: 'description', name: 'Description', field: 'description' },
{ id: 'duration', name: 'Duration (days)', field: 'duration', type: FieldType.number },
];
this.gridOptions = {
enableExcelCopyBuffer: true,
};
```

### Copy & Paste with Cell Formatter
What if you have a date in UTC format in your dataset but your grid shows it as a Date ISO format? In that case, you are using a Formatter (e.g. `formatter: Formatters.dateIso`) and you wish to use that formatter. Good news, that is supported with and to make is simpler for the implementation, we will use a flag that already exist which is `exportWithFormatter` and is used by the `Export to File` service (for more info, read [Wiki - Export to File](Export-to-Text-File.md)

The `exportWithFormatter` can be used in 2 ways, on each column definition independently or for the entire grid through it's grid option.
##### `exportWithFormatter` through each Column Definition
```typescript
this.columnDefinitions = [
{
id: 'start', name: 'Start', field: 'start',
formatter: Formatters.dateIso,
exportWithFormatter: true
},
{
id: 'finish', name: 'Finish', field: 'finish',
formatter: Formatters.dateIso,
exportWithFormatter: true
},
];

this.gridOptions = {
enableExcelCopyBuffer: true,
};
```

##### `exportWithFormatter` through Grid Options
```typescript
this.columnDefinitions = [
{ id: 'start', name: 'Start', field: 'start', formatter: Formatters.dateIso },
{ id: 'finish', name: 'Finish', field: 'finish', formatter: Formatters.dateIso },
];

this.gridOptions = {
enableExcelCopyBuffer: true,
exportOptions: {
// set at the grid option level, meaning all column will evaluate the Formatter (when it has a Formatter defined)
exportWithFormatter: true
},
};
```
#### Sanitize Formatter Ouput
In some cases a Formatter can be formed of HTML and that will end up showing in your Copy+Paste. You can simply use the `sanitizeDataExport` flag which will remove any HTML tags from the output. For an example below, let say that our first Title column are all displayed in bold in the grid (e.g. `<b>Title 1</b>`), we want to sanitize that output a regular text output (e.g. `Title 1`)

##### `exportWithFormatter` through each Column Definition
```typescript
this.columnDefinitions = [
{
id: 'title', name: 'Title', field: 'id',
formatter: Formatters.bold,
exportWithFormatter: true,
sanitizeDataExport: true
}
];

this.gridOptions = {
enableExcelCopyBuffer: true
};
```

##### `exportWithFormatter` through Grid Options
```typescript
this.columnDefinitions = [
{ id: 'title', name: 'Title', field: 'id', formatter: Formatters.bold }
];

this.gridOptions = {
enableExcelCopyBuffer: true,
exportOptions: {
exportWithFormatter: true,
sanitizeDataExport: true
},
};
```

### Disable pasting on specific columns
If you want to disable pasting values for specific columns you can deactivate it using the denyPaste property on the Column config.

```typescript
this.columnDefinitions = [
{
id: 'colA', name: 'Col A', field: 'col_a',
formatter: Formatters.bold,
exportWithFormatter: true,
sanitizeDataExport: true,
denyPaste: true // <------------
}
];
```

This will even work in situations where your table copy buffer stretches over disabled cells, by simply skipping them. So for the following config (x = paste disabled; o = paste enabled), pasting a 3 cell stretching table buffer will result in Col A and C being updated but ColB ignoring the paste and keeping its original value

Col A | Col B | Col C \
\---------------------\
&nbsp;&nbsp; o &nbsp;&nbsp; | &nbsp;&nbsp;&nbsp; x &nbsp;&nbsp; | &nbsp;&nbsp;&nbsp; o \
NEW | &nbsp;&nbsp;&nbsp; x &nbsp;&nbsp; | &nbsp;NEW

### Disable pasting on specific cells
If you need even more fine grained control, you can make use of the gridOption `onBeforePasteCell`:

```typescript
this.gridOptions = {
enableExcelCopyBuffer: true,
excelCopyBufferOptions: {
onBeforePasteCell: (e, args) => {
// e.g deny paste on first cell
return args.cell > 0;
}
}
};
```

This way you have full control, via the args parameters, to get a ref to the current row and cell being updated. Also keep in mind that while performing a buffered table paste (e.g three cols at once) and only one of them has a denying condition, the other cells paste will pass successfully.
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import {
type Column,
type DOMEvent,
emptyElement,
type Formatter,
Formatters,
type GridOption,
Expand Down
10 changes: 9 additions & 1 deletion examples/vite-demo-vanilla-bundle/src/examples/example19.html
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
<style>
.blocked-cell {
background: darkred!important;
color: #999;
}

</style>
<h3 class="title is-3">
Example 19 - ExcelCopyBuffer with Cell Selection
<span class="subtitle">(with Salesforce Theme)</span>
Expand All @@ -11,7 +18,8 @@ <h3 class="title is-3">
</h3>

<h5 class="title is-5 mb-3">
Grid - using <code>enableExcelCopyBuffer</code> which uses <code>SlickCellSelectionModel</code>
Grid - using <code>enableExcelCopyBuffer</code> which uses <code>SlickCellSelectionModel</code><br />
The complete first row and the cells C - E of the second row are not allowing to paste values.
</h5>
<h6 class="title is-6">
<button class="button is-small is-primary" onclick.delegate="togglePagination()"
Expand Down
22 changes: 20 additions & 2 deletions examples/vite-demo-vanilla-bundle/src/examples/example19.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,20 @@ export default class Example19 {
targetRange.textContent += JSON.stringify(slickRange);
}
});

const hash = {
0: {},
1: {
2: 'blocked-cell',
3: 'blocked-cell',
4: 'blocked-cell',
}
};
for ( let i = 0; i < NB_ITEMS; i++) {
hash[0][i] = 'blocked-cell';
}

this.sgb.slickGrid?.setCellCssStyles(`blocked-cells`, hash);
}

dispose() {
Expand Down Expand Up @@ -88,11 +102,15 @@ export default class Example19 {

// when using the ExcelCopyBuffer, you can see what the selection range is
enableExcelCopyBuffer: true,
// excelCopyBufferOptions: {
excelCopyBufferOptions: {
// onCopyCells: (e, args: { ranges: SelectedRange[] }) => console.log('onCopyCells', args.ranges),
// onPasteCells: (e, args: { ranges: SelectedRange[] }) => console.log('onPasteCells', args.ranges),
// onCopyCancelled: (e, args: { ranges: SelectedRange[] }) => console.log('onCopyCancelled', args.ranges),
// }
onBeforePasteCell: (_e, args) => {
// deny the whole first row and the cells C-E of the second row
return !(args.row === 0 || (args.row === 1 && args.cell > 2 && args.cell < 6));
}
}
};
}

Expand Down
Loading

0 comments on commit 22037ca

Please sign in to comment.