Skip to content

Commit

Permalink
feat(plugin): new Row Based Editor (#1323)
Browse files Browse the repository at this point in the history
  • Loading branch information
zewa666 authored Jan 18, 2024
1 parent e02ac55 commit 64d464c
Show file tree
Hide file tree
Showing 28 changed files with 2,164 additions and 8 deletions.
1 change: 1 addition & 0 deletions docs/TOC.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
* [Pinning (frozen) of Columns/Rows](grid-functionalities/frozen-columns-rows.md)
* [Row Selection](grid-functionalities/Row-Selection.md)
* [Tree Data Grid](grid-functionalities/Tree-Data-Grid.md)
* [Row Based Editing Plugin](grid-functionalities/Row-based-edit.md)

## Backend Services

Expand Down
6 changes: 5 additions & 1 deletion docs/column-functionalities/Editors.md
Original file line number Diff line number Diff line change
Expand Up @@ -369,4 +369,8 @@ For SalesForce it's nearly the same, the only difference is that we add our even
<div class="grid-container slds-p-horizontal">
<div class="grid1" onslickergridcreated={handleOnSlickerGridCreated}>
</div>
</div>
</div>
```

## Turning individual rows into edit mode
Using the [Row Based Editing Plugin](../grid-functionalities/Row-based-edit.md) you can let the user toggle either one or multiple rows into edit mode, keep track of cell changes and either discard or save them on an individual basis using a custom `onBeforeRowUpdated` hook.
70 changes: 70 additions & 0 deletions docs/grid-functionalities/Row-based-edit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#### index
- [The action column](#the-action-column)
- [Multiple Row Selections](#multiple-row-selections)
- [Change Dynamically Single/Multiple Selections](#changing-dynamically-from-single-to-multiple-selections-and-vice-versa)
- [Mixing Single & Multiple Row Selections](#mixing-single--multiple-row-selections)
- [Disable Custom Rows Selections via `selectableOverride`](#disable-custom-rows-selections-via-selectableoverride)
- [Disable External Button when having Empty Selection](#disable-external-button-when-having-empty-selection)
- [Change Row Selections](#change-row-selections)
- Troubleshooting
- [Adding a Column dynamically is removing the Row Selection, why is that?](#adding-a-column-dynamically-is-removing-the-row-selection-why-is-that)

### Description
The Row based editing plugin makes it possible to keep the grid readonly except for rows which the user explicitely toggles into edit mode.

**Note:** This plugin enforces the use of the `autoEdit` option and will turn it on with a console warning if its not already.

### Demo
[Demo Page](https://ghiscoding.github.io/slickgrid-universal/#/example22) / [Demo ViewModel](https://github.com/ghiscoding/slickgrid-universal/blob/master/examples/webpack-demo-vanilla-bundle/src/examples/example22.ts)

## The action column
A new column is rendered that shows an edit/delete button. If the user clicks on edit, a save and cancel button are shown instead and the row toggles into edit mode. By default as the last column but you can override it with the option `columnIndexPosition`. Additionally it's default column id can be overriden using the opiton `columnId`. Furthermore, you can also override the columns label via the `actionsColumnLabel` property.

### Single or multiple editable rows
By default you can only toggle a single row into edit mode. If you set the option `allowMultipleRows` to `true` on the other hand, you can toggle as many as you want.

### Configuring the action buttons
You can override the styling, the hover text as well as whether a prompt — and with what text — should be shown. It is done by overriding the `actionButtons` property of the [plugins options](https://github.com/ghiscoding/slickgrid-universal/blob/master/packages/common/src/interfaces/rowBasedEditOption.interface.ts).

## Support for the Excel Copy Buffer Plugin
If the [Excel Copy Buffer Plugin](excel-copy-buffer.md) is configured, the Row based editing pluging will override it's behavior by denying pastes on all cells not within a edit mode row. Nevertheless, any existing `BeforePasteCellHandler` will be respected.

## How the plugin works
The idea of the plugin is to focus the users editing experience on specific individual rows and and save them individually. This is achieved by letting the user toggle one or more rows into edit mode. Now changes can be made to those rows and will be highlighted and tracked. The user may cancel the edit mode at any time and revert all cells changes. If the save button is pressed on the other hand an `onBeforeRowUpdated` hook, which you define via plugin options, is called and expects a `Promise<boolean>`. In that method you'd typically write the changes to your backend and return either true or false based on the operations outcome. If a negative boolean is returned the edit mode is kept, otherwise the row applies the changes and toggles back into readonly mode. That means, no modifications can be done on the grid.

Here's the respective code shown in Example22:

#### ViewModel
```ts
onBeforeRowUpdated(args) {
const { effortDriven, percentComplete, finish, start, duration, title } = args.dataContext;

if (duration > 40) {
alert('Sorry, 40 is the maximum allowed duration.');
return Promise.resolve(false);
}

return fakeFetch('your-backend-api/endpoint', {
method: 'POST',
body: JSON.stringify({ effortDriven, percentComplete, finish, start, duration, title }),
headers: {
'Content-type': 'application/json; charset=UTF-8'
}
}).catch(err => {
console.error(err);
return false;
})
.then(response => {
if (response === false) { // <---- the negative response, e.g validation failed, keep the row as is
return false;
}
if (typeof response === 'object') {
return response!.json();
}
})
.then(json => {
alert(json.message);
return true; // <--- all good, apply changes in grid and toggle row into readonly mode
});
},
```
4 changes: 3 additions & 1 deletion examples/vite-demo-vanilla-bundle/public/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -99,5 +99,7 @@
"TASK_X": "Task {{x}}",
"TITLE": "Title",
"TRUE": "True",
"X_DAY_PLURAL": "{{x}} day{{plural}}"
"X_DAY_PLURAL": "{{x}} day{{plural}}",
"RBE_BTN_UPDATE": "Update the current row",
"RBE_BTN_CANCEL": "Cancel changes of the current row"
}
4 changes: 3 additions & 1 deletion examples/vite-demo-vanilla-bundle/public/i18n/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -100,5 +100,7 @@
"TITLE": "Titre",
"TITLE.NAME": "Nom du Titre",
"TRUE": "Vrai",
"X_DAY_PLURAL": "{{x}} journée{{plural}}"
"X_DAY_PLURAL": "{{x}} journée{{plural}}",
"RBE_BTN_UPDATE": "Mettre à jour la ligne actuelle",
"RBE_BTN_CANCEL": "Annuler la ligne actuelle"
}
2 changes: 2 additions & 0 deletions examples/vite-demo-vanilla-bundle/src/app-routing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import Example18 from './examples/example18';
import Example19 from './examples/example19';
import Example20 from './examples/example20';
import Example21 from './examples/example21';
import Example22 from './examples/example22';

export class AppRouting {
constructor(private config: RouterConfig) {
Expand Down Expand Up @@ -49,6 +50,7 @@ export class AppRouting {
{ route: 'example19', name: 'example19', view: './examples/example19.html', viewModel: Example19, title: 'Example19', },
{ route: 'example20', name: 'example20', view: './examples/example20.html', viewModel: Example20, title: 'Example20', },
{ route: 'example21', name: 'example21', view: './examples/example21.html', viewModel: Example21, title: 'Example21', },
{ route: 'example22', name: 'example22', view: './examples/example22.html', viewModel: Example22, title: 'Example22', },
{ route: '', redirect: 'example01' },
{ route: '**', redirect: 'example01' }
];
Expand Down
3 changes: 3 additions & 0 deletions examples/vite-demo-vanilla-bundle/src/app.html
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,9 @@ <h4 class="title is-4 has-text-white">Slickgrid-Universal</h4>
<a class="navbar-item" onclick.delegate="loadRoute('example21')">
Example21 - Row Detail View
</a>
<a class="navbar-item" onclick.delegate="loadRoute('example22')">
Example22 - Row Based Editing
</a>
</div>
</div>
</div>
Expand Down
72 changes: 72 additions & 0 deletions examples/vite-demo-vanilla-bundle/src/examples/example22.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<h3 class="title is-3">
Example 22 - Row Based Editing
<span class="subtitle">(with Salesforce Theme)</span>
<div class="subtitle code-link">
<span class="is-size-6">see</span>
<a
class="is-size-5"
target="_blank"
href="https://github.com/ghiscoding/slickgrid-universal/blob/master/examples/vite-demo-vanilla-bundle/src/examples/example22.ts"
>
<span class="mdi mdi-link-variant mdi-v-align-sub"></span> code
</a>
</div>
<h6 class="title is-6 italic content">
<ul>
<li>
The Row Based Edit plugin allows you to edit either a single or multiple
specific rows at a time, while disabling the rest of the grid rows.
</li>
<li>
Editedable rows, as well as modified cells are highlighted with a
different color, which you can customize using css variables (see
<a
target="_blank"
href="https://github.com/ghiscoding/slickgrid-universal/blob/master/examples/vite-demo-vanilla-bundle/src/examples/example22.scss"
>
example22.scss </a
>)
</li>
<li>
Modifications are kept track of and if the cancel button is pressed, all
modifications are rolled back.
</li>
<li>
If the save button is pressed, a custom "onBeforeRowUpdated" callback is called, which you can use to save the data with your backend.<br />
The callback needs to return a Promise&lt;boolean&gt; and if the promise resolves to true, then the row will be updated, otherwise it will be cancelled and stays in edit mode.
You can try out the later by defining a Duration value <b>larger than 40</b>.
<br />
<small><span class="has-text-danger">NOTE:</span> You can also combine this with e.g. Batch Editing like shown <a href="#/example11">in Example 11</a></small>
</li>
<li>
This example additionally uses the ExcelCopyBuffer Plugin, which you can see also in <a href="#/example19">example 19</a>.
The example defines a rule that pastes in the first column are prohibited. In combination with the Row Based Editing Plugin though, this rule gets enhanced with the fact
that only the edited rows are allowed to be pasted into, while still respecting the original rule.
</li>
</ul>
</h6>
</h3>

<section>
<div class="row mb-1">
<button
class="button is-small"
data-test="single-multi-toggle"
onclick.delegate="toggleSingleMultiRowEdit()"
>
Toggle Single/Multi Row Edit
</button>
<button
class="button is-small"
data-test="toggle-language"
onclick.delegate="switchLanguage()"
>
Switch Language for Action column buttons
</button>
<b>Locale:</b>
<span class="text-italic" data-test="selected-locale" textcontent.bind="selectedLanguageFile">
</span>
</div>
</section>

<div class="grid1"></div>
9 changes: 9 additions & 0 deletions examples/vite-demo-vanilla-bundle/src/examples/example22.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
:root {
// turn on/off the following variables to see the difference in styling

// --slick-row-based-edit-editmode-bgcolor: rgb(82, 235, 158);
// --slick-row-based-edit-editmode-hover-bgcolor: cyan;
// --slick-row-based-edit-unsaved-cell-bgcolor: rgb(190, 114, 127);
// --slick-row-based-edit-editmode-active-bgcolor: rgb(82, 235, 158);
// --slick-row-based-edit-editmode-active-hover-bgcolor: cyan;
}
Loading

0 comments on commit 64d464c

Please sign in to comment.