# Upgrade guide for Grid v4.0.0

## Dropped support for Edge 18 and older

We are not actively removing the fixes we have in place yet, but moving forward we will no longer add new fixes for
versions of Edge <= 18. If you are using an old version of Edge, we strongly encourage you to update to a new blink
based version.

Existing fixes are planned to be removed in version 5.0.

## New grid.lite.umd.js bundle to use with Angular

Bryntum Grid is delivered with a new UMD package without polyfills. This was done to avoid conflicts with any external
Promise polyfills, such as `ZoneAwarePromise` from `zone.js` for Angular applications. It fixes this runtime error:

```shell
Zone.js has detected that ZoneAwarePromise (window|global).Promise has been overwritten.
Most likely cause is that a Promise polyfill has been loaded after Zone.js 
(Polyfilling Promise api is not necessary when zone.js is loaded. If you must load one, do so before loading zone.js.)
```

We recommend that all your Angular applications should be upgraded to use the new `grid.lite.umd.js` bundle. Also, there
should be no polyfills imported in `app/src/polyfills.ts` after `import 'zone.js/dist/zone';`. We have updated all our
Angular examples to use this new bundle. Make sure to update all usages of `grid.umd.js` to `grid.lite.umd.js` within
your application to avoid `Bundle included twice` runtime error.

**Old code:**

```javascript
import { Grid, Model, Store } from 'bryntum-grid/grid.umd.js';
```

**New code:**

```javascript
import { Grid, Model, Store } from 'bryntum-grid/grid.lite.umd.js';
```

If you wish to have IE/Edge compatibility, please follow the instructions in `app/src/polyfills.ts`.

## State

State was refactored to use a slightly different format which might affect end users, any stored subGrid width/collapsed
states will be reset. This is of course a temporary problem, as soon as users save state again, all will work as
expected.

## Grid extends Panel

The `Grid` class (and therefore `Scheduler` and `Gantt`) now extends `Panel`. This means that they can have
embedded `tbar` and `bbar` and `header` components to offer a richer UI right inside the Grid.

```javascript
new Grid({
    appendTo : myElement,
    store    : myStore,

    // Will show a header containing the title
    title : 'My Data Grid',

    // Will show a top toolbar. Note that 'loadButton' will be available in the Grid's `widgetMap`
    tbar    : {
        items : {
            loadButton : {
                text : 'Reload',
                onClick() {
                    myStore.reload();
                }
            }
        }
    },
    columns : [/*...*/]
});
```

## Store can accept a raw JSON string

Store's `json` property now accepts a JSON string and applies it to its `data` property, so the `json` property can be
bound to a JSON data source to keep a grid's data up to date.

The `json` accessor yields a JSON string representation of the current data load.

## WidgetHelper and BryntumWidgetAdapter

Registration of Widget classes for subsequent resolution through the `type` property of config objects has been
simplified. The "Adapter" concept has been removed. Widget classes now register themselves with the `Widget` base class
which is where they can also be looked up. When creating a custom widget, implement the `static get type` property to
return the type name. And at the end simply call `MyWidgetClass.initClass()` to have the new Widget class register
itself.

**Old code:**

```javascript
class MyWidget extends Widget {

}

BryntumWidgetAdapterRegister.register('mywidget', MyWidget);
```

**New code:**

```javascript
class MyWidget extends Widget {
    static get type() {
        return 'mywidget';
    }
}

MyWidget.initClass();
```

Fewer widgets are auto imported with the removal of the Adapter which imported a base set of Widgets. This means that
when not using a bundle, application code must import the widgets it uses. It also means that custom builds may be
smaller by including only what is used.

If your code previously had:

```javascript
import 'lib/Core/adapter/widget/BryntumWidgetAdapter.js';
import WidgetHelper from 'lib/Core/helper/WidgetHelper.js';

WidgetHelper.append([
    {
        type : 'button',
        text : 'Click'
    }
], /*...*/);
```

It should now instead not import the adapter, and instead directly import the button:

```javascript
import WidgetHelper from 'lib/Core/helper/WidgetHelper.js';
import 'lib/Core/widget/Button.js';

WidgetHelper.append([
    {
        type : 'button',
        text : 'Click'
    }
], /*...*/);
```

## Context menu refactoring

### Basic class

New abstract ContextMenuBase class was introduced. It has common logic for all context menu features. It creates a new
menu instance, handles event firing, and provides basic functions to work with the menu.

### ContextMenu feature

ContextMenu feature was replaced by CellMenu and HeaderMenu. So now context menu is configured for cells and headers
independently. Items are named objects now:

**Old code:**

```javascript
const grid = new Grid({
    features : {
        contextMenu : {
            headerItems : [
                { text : 'My header item', onItem : () => {/*...*/} }
            ],

            cellItems : [
                { text : 'My cell item', onItem : () => {/*...*/} }
            ],

            processCellItems({ items, record }) {
                if (record.cost > 5000) {
                    items.push({ text : 'Split cost' });
                }
            }
        }
    }
});
```

**New code:**

```javascript
const grid = new Grid({
    features : {
        headerMenu : {
            items : {
                myItem : { text : 'My header item', onItem : () => {/*...*/} }
            }
        },

        cellMenu : {
            items : {
                myItem : { text : 'My cell item', onItem : () => {/*...*/} }
            },

            processItems({items, record}) {
                if (record.cost > 5000) {
                    items.costItem = { text : 'Split cost' };
                }
            }
        }
    }
});
```

### showRemoveRowInContextMenu config

Grid's `showRemoveRowInContextMenu` config was deprecated in favour of `CellMenu` config. So to remove a default item
please follow this way:

**Old code:**

```javascript
const grid = new Grid({
    showRemoveRowInContextMenu : false
});
```

**New code:**

```javascript
const grid = new Grid({
    features : {
        cellMenu : {
            items : {
                removeRow : false // `removeRow` is a key of default "Remove row" item
            }
        }
    }
});
```

### cellMenuItems and headerMenuItems column configs

Column's `cellMenuItems` and `headerMenuItems` configs were turned into named objects:

**Old code:**

```javascript
const grid = new Grid({
    columns : [
        {
            text            : 'First name',
            field           : 'firstName',
            headerMenuItems : [
                { text : 'Column specific header item' }
            ],
            cellMenuItems : [
                { text : 'Column specific cell item' }
            ]
        }
    ]
});
```

**New code:**

```javascript
const grid = new Grid({
    columns : [
        {
            text            : 'First name',
            field           : 'firstName',
            headerMenuItems : {
                firstColumnItem : { text : 'Column specific header item' }
            },
            cellMenuItems : {
                firstColumnItem : { text : 'Column specific cell item' }
            }
        }
    ]
});
```

### Context menu events

Some of Grid's events provided by ContextMenu feature were replaced by CellMenu and HeaderMenu features. Here is the
list of changes:

- `cellContextMenuBeforeShow` -> `cellMenuBeforeShow`;
- `cellContextMenuShow` -> `cellMenuShow`;
- `headerContextMenuBeforeShow` -> `headerMenuBeforeShow`;
- `headerContextMenuShow` -> `headerMenuShow`;
- `contextMenuItem` -> `cellMenuItem` and `headerMenuItem`;
- `contextMenuToggleItem` -> `cellMenuToggleItem` and `headerMenuToggleItem`;

For example:

**Old code:**

```javascript
const grid = new Grid({
    listeners : {
        cellContextMenuBeforeShow   : () => {/*...*/},
        cellContextMenuShow         : () => {/*...*/},
        headerContextMenuBeforeShow : () => {/*...*/},
        headerContextMenuShow       : () => {/*...*/},
        contextMenuItem             : () => {/*...*/},
        contextMenuToggleItem       : () => {/*...*/}
    }
});
```

**New code:**

```javascript
const grid = new Grid({
    listeners : {
        cellMenuBeforeShow   : () => {/*...*/},
        cellMenuShow         : () => {/*...*/},
        cellMenuItem         : () => {/*...*/},
        cellMenuToggleItem   : () => {/*...*/},
        headerMenuBeforeShow : () => {/*...*/},
        headerMenuShow       : () => {/*...*/},
        headerMenuItem       : () => {/*...*/},
        headerMenuToggleItem : () => {/*...*/}
    }
});
```

## Model Field Inheritance

Fields defined in a derived class Model that coincide by name with a field declared in a super class will now only
override those field config properties specified by the derived class. This allows derived classes to adjust a field
definition in one way, say to change the default value and still inherit other field properties, such as a convert
function.

For example:

```javascript
    class ModelOne extends Model {
    static get fields() {
        return [
            { name : 'barcode', convert : v => String(v) }
        ];
    }
}

class ModelTwo extends ModelOne {
    static get fields() {
        return [
            { name : 'barcode', defaultValue : 'ABC123' }
        ];
    }
}
```

In previous releases, `ModelTwo` would have had to redefine the `convert` config for the `barcode` field.

## Renamed CSS themes

The `Default`, `Light` and `Dark` themes were renamed to `Classic`, `Classic-Light` and `Classic-Dark`. This change
highlights the fact that they are variations of the same theme, and that it is not the default theme (Stockholm is our
default theme since version 2.0).

If you are using one of these themes, you will have to adjust your css import to match the new name.

**Old code:**

```html
<link rel="stylesheet" href="build/grid.dark.css" id="bryntum-theme">
```

**New code:**

```html
<link rel="stylesheet" href="build/grid.classic-dark.css" id="bryntum-theme">
```

If you have theme specific selectors in your code/CSS you have to adjust those also:

**Old code:**

```css
.b-theme-dark {
/*...*/
}
```

**New code:**

```css
.b-theme-classic-dark {
/*...*/
}
```

### RowReorder feature

The RowReorder feature now supports dragging multiple rows and the `record` property previously part of the events fired
is now renamed to `records` and is an `Array` of records.

**Old code:**

```javascript
grid.on('gridRowDrop', event => {
    console.log(event.context.record.name);
});
```

**New code:**

```javascript
grid.on('gridRowDrop', event => {
    console.log(event.context.records[0].name);
});
```

## Deprecations

### StringHelper

The `capitalizeFirsLetter()` and `lowerCaseFirstLetter()` functions in `StringHelper` was deprecated in favor of
`capitalize()` and `uncapitalize()`. The old functions are directly swappable for the new. If you are using one of these
functions, please rename your usages.

**Old code:**

```javascript
StringHelper.capitalizeFirstLetter('batman'); // Batman
StringHelper.lowercaseFirstLetter('Joker');   // joker
```

**New code:**

```javascript
StringHelper.capitalize('batman');  // Batman
StringHelper.uncapitalize('Joker'); // joker
```

## Accessibility

A change was made to allow keyboard navigation from a Grid column header to the rows below using the **down** arrow key.
Earlier this triggered the column menu to show, the menu can be triggered with the *space bar* key. Pressing down arrow
from a grid column header, will now put focus at the first fully visible cell of that column.


<p class="last-modified">Last modified on 2023-10-26 8:19:11</p>