Managing AdapTable State

This guide looks at how AdapTable manages User State at run-time.

important

See Predefined Config for extensive information on how to pre-populate a new AdapTable instance with initial User State at design-time.

Managing User State is one of the most valued pieces of functionality that AdapTable provides.

note

User State includes state provided at design-time (through Predefined Config) and that created at run-time through user action (e.g. selecting a Layout, creating a Column Filter etc.)

AdapTable automatically saves User State as it changes - meaning that the next time the Application is reloaded, the user sees the same state as on the previous visit.

tip

Internally AdapTable uses Redux to manage its state - this provides a unidirectional store for all the objects used in the grid. This means that if you are also using Redux in your own application, then you should continue to use your own Store and not merge the 2 Stores.

Adaptable State Storage Options

There are 2 modes of storage available in AdapTable:

  • Local Storage - by default, Adaptable State is stored in the browser's local storage using the unique adaptableId property provided in Adaptable Options.

    caution

    If using Local Storage, all user state will be lost each time the user clear's the browser cache and will not be available when switching computer.

  • Remote Storage - Adaptable state will be persisted to, and retrieved from, a remote location which you manage via State Options functions.

State Options

State Options contain a series of useful JavaScript function hooks which allow developers to control the management of Adaptable State.

The full list of properties is as follows:

PropertyDescriptionDefault
applyStateAllows hooking into AdaptableState hydration
clearStateAllows clearing of remote state.
debounceStateDelayDelay (in ms) to debounce saveState/persistState calls enabling grouping multiple sequential calls in single one (e.g. elevator doors)400
loadStateAllows the customization of state loading.
persistStateAllows the customization of state persistence.
saveStateAllows the customization of the state that is going to be persisted

AdapTable provides 4 function hooks which support custom implementations / functionality when state is being managed.

This allows you to provide your own hydration or rehydration functionality or to enrich the State when its being loaded with your own items (e.g. entitlements).

The various state-management functions provided here allow you to change this default behaviour, and also to add custom properties in the persisted state.

The 4 functions you can provide your own implementations for are:

  • loadState: Allows the customization of state loading.

  • applyState: Allows hooking into AdaptableState hydration

  • saveState: Allows the customization of the state that is going to be persisted

  • persistState: Allows the customization of state persistence

Adaptable State Flow

The Adaptable State flow is as follows:

  1. User Loads Page --> loadState() state1 -> applyState(state1)
  2. state2 ---- ADAPTABLE NOW READY WITH STATE (state2)
  3. User Updates State ------ saveState(state3):
  4. state4 -> persistState(state4)

persistState

Allows the customization of state persistence.

important

By default, state is stringified using JSON.stringify and persisted into the localStorage, at the key denoted by adaptableId.

This function can be used to change this behaviour, throttle state persistence, etc.

If defined, most likely it should be used in conjunction with loadState, which is the other side of the persistence mechanism.

The persistence (dehydration) flow is the following: saveState -> persistState.

tip

If you want to add other properties on the state that is going to be persisted, use saveState.

Whatever that returns is then passed to persistState.

Default implementation

Stringifies the state and puts it into the localStorage using the adaptableId key

loadState

Allows the customization of state loading.

important

By default, AdapTable will read the state that was persisted from localStorage (at the adaptableId key) and returns it.

If this function is defined, most likely it will be used in conjunction with persistState, which is the other side of the persistence mechanism.

tip

For example, loadState can be used to load Adaptable State from the browser window object or from a remote location altogether.

The hydration flow is the following: loadState -> applyState

So whatever loadState returns, is passed to applyState.

Default implementation

For local predefinedConfig, it reads the state from localStorage<adaptableId> and parses it as a JavaScript object, which is returned.

saveState

Allows the customization of the state that is going to be persisted.

tip

If you simply want to add other properties to the state, before persistence, use this function

adaptableOptions = {
stateOptions: {
saveState: (state) => {
return {
...state,
userSettings: {
language: 'de'
}
}
}
}
}

In this case, you might find it useful to also define applyState which hooks into state hydration, and gives you access to the persisted custom properties, so you can use them later in the app.

note

If you also want to modify the persistence behaviour, you have to implement the persistState as well.

The persistence (dehydration) flow is the following: saveState -> persistState

important

You have to make sure that the returned object is serializable with JSON.stringify - in case that it's not, you could define persistState to do a custom serialization of the object.

caution

This function should be a synchronous function.

Default implementation

(state) => state

applyState

Allows hooking into Adaptable State hydration.

important

This function determines what state is (re)applied in AdapTable when AdapTable is initialized.

This is useful when saveState was specified and added new custom properties, which will again be accessible into the applyState function.

tip

If you used saveState to add custom app-specific properties on the top-level object you returned, it's a good practice to clear these properties and just return Adaptable State from this function.

adaptableOptions = {
stateOptions: {
saveState: (state) => {
return {
...state,
userSettings: {
language: 'de'
}
}
},
applyState: (state) => {
const { userSettings, ...adaptableState } = state
// do something with userSettings here
return adaptableState
}
}
}

The hydration flow is the following: loadState -> applyState

So whatever loadState returns, is passed to this function.

caution

This function should be a synchronous function.

Default implementation

(state) => state

State Options Example

const adaptableOptions: AdaptableOptions = {
primaryKey: 'OrderId',
userName: 'Demo User',
adaptableId: 'State Functions Demo',
stateOptions: {
/**
* The loadState function is used to load the predefined config
* from a remote source - namely firebase in this example
*
* It returns a promise which is resolved when the
* Predefined Config is retrieved from firebase.
*/
loadState: () => {
return firebase
.database()
.ref(`predefinedconfig/${id}`)
.once('value')
.then(function(snapshot) {
const str = snapshot.val();
return str ? JSON.parse(str) : {};
});
},
/**
* The persistState function is called with the state that needs to be persisted.
* By default, state is persisted in localStorage, but this example
* illustrates how you can persist it to a remote datastore (e.g. Firebase)
*/
persistState: (state: Partial<AdaptableState>) => {
return firebase
.database()
.ref(`predefinedconfig/${id}`)
.set(JSON.stringify(state))
.then(() => Promise.resolve(true));
},
},
predefinedConfig: demoConfig,
vendorGrid: { ...gridOptions, modules: AllEnterpriseModules },
};

Accessing Adaptable State

Developers have full, run-time access to the Adaptable State Store is via the Adaptable Api).

Among many other advantages, the Adaptable Api provides full, programmatic, read / write access to all Adaptable State objects in a 'clean' and safe way.

note

The Adaptable Api is effectively a wrapper around our Redux store with some additional error handling, logging and other features.

Listening to State Changes

The best way to listen to changes in the Store is to subscribe to Adaptable State Changed Event.

This event fires whenever anything in the State changes; it provides the Action that caused the change (with full details) as well as before and after copies of Adaptable State.

See Audt Log for a full list of available State Changed Actions.

Clearing Adaptable State

The easiest way to clear any Adaptable State added by a user is to provide a bespoke implementation for the clearState function in State Options.

This function enables Remote State to be cleared and is called by AdapTable whenever User State is cleared (so that State will return to whatever is in the initial Predefined Config).

note

One instance is the reloadPredefinedConfig function in Config Api which will call this function if an implementation has been provided

Bespoke Items in Adaptable State

Bespoke data can be stored in AdapTable State via the ApplicationDataEntries property in the Application State section of Predefined Config.

This provides an array of key / value pairs which AdapTable will persist with the rest of the state.

Application Predefined Config

The Application Predefined Config is as defiend as follows:

PropertyDescription
ApplicationDataEntriesArray of Key / Value pairs enabling custom data to be stored in Adaptable State.

Each ApplicationDataEntry is a simple Key / Value pair object defined as follows:

PropertyDescription
KeyKey of Key / Value pair - always stored as a string
ValueValue of Key / Value pair (actual data being stored) - needs to stringifiable
caution

The only restriction is that was is stored in the Value can be stringified - as it will be persistd as JSON.

export default {
Application: {
ApplicationDataEntries:[
{
Key: 'Name',
Value: 'John Smith',
},
{
Key: 'Employee Number',
Value: 20283728,
},
{
Key: 'Joined Date',
Value: new Date(2017, 13, 7),
},
{
Key: 'Super User',
Value: false,
},
],
}
} as PredefinedConfig;

Application API Methods

The Application API section of AdapTable API provides access to Application State, where developers can store their own bespoke data using ApplicationDataEntry array (Key / Value Pairs).

MethodDescription
addApplicationDataEntry(applicationDataEntry)Adds new Application Data Entry
createApplicationDataEntry(key, value)Creates new Application Data Entry with given Key and Value
deleteApplicationDataEntry(applicationDataEntry)Deletes given Application Data Entry
editApplicationDataEntry(applicationDataEntry)Edits given Application Data Entry
getApplicationDataEntries()Retrieves all Key Value Pairs in Application state
getApplicationDataEntriesByValue(value)Gets Application Data Entry with given value
getApplicationDataEntryByKey(key)Gets Application Data Entry with given key
getApplicationState()Retrieves Application section from Adaptable State

Multiple 'Views' (or State sections)

Advanced Users of AdapTable often ask how they can create multiple 'Views' - ie. different, separate, named collections of Adaptable State - and switch between them at run-time.

caution

A View in this scenario is not the same as a Layout as that stores Column information only, while a 'View' can contain multiple different sections of Predefined Config.

This is possible in AdapTable and pretty straightforward to do by leveraging the adaptableStateKey property of Adaptable Options and the setAdaptableStateKey method in Config Api.

tip

The Multiple Views demo provides one possible example for how to do this.

Retrieving State at run-time

The Config Api section of Adaptable Api contains many methods for retrieiving and managing Adaptable State.

Additionally the State Management Module contains a button to clear current User State and a series of helper methods to export State, User State or Predefined Config to various destinations.

State Management Module

AdapTable offer the State Management Module as a run-time way of managing and retrieving State.

UI Elements

The State Management Popup contains 3 elements:

  • Clear User State button - removes all current User state and reloads the initial Predefined Config

  • Load Predefined Config button - allows a JSON file to be selected and the loaded, which will be treated as new Predefined Config

  • Export State dropdowns - exports 3 types of state:

    • All State
    • User State
    • Predefined Config

    to all of 3 destinations:

    • a JSON file
    • clipboard
    • console

UI Entitlements

UI Entitlements behaviour is as expected for Full and Hidden Access Levels.

The ReadOnly Entitlement behaviour is that the 'Retrieve State' dropdowns operate but the 'Delete State' button is disabled.

FAQ

Where is Adaptable State stored?

By default it is stored in the local browser cache. However you can use the State Options functions to choose to save your state in any location that you specify (as well as to enrich it en route).

Do you provide data adapters to fetch / save Adaptable State?

No we don't, you will need to provide the mechanism to store configuration in a remote location.

There are simply too many different storage locations and mechnisms for it to make sense for us to provide connectors.

Can I preconfigure my AdapTable instance?

Yes you can. You are able to build your own Adaptable Objects which are stored as Predefined Config. You then provide this configuration as a JSON object or as a URL (to a .JSON file) in Adaptable Options.

Can I provide different Predefined Config per user?

Yes, that is possible and expected. AdapTable allows you provide highly configurable and personalised instances.

Can we store our own data in the AdapTable State / Predefined Config?

Yes you can. Use the AdaptableEntries property of Application State.

This provides an array of key / value pairs which you can use to store your own bespoke data and AdapTable will persist it with the rest of the state.

Is there a restriction on what we can store in AdapTable Entries?

Yes, it needs to be something that can be JSON stringified so it cannot be a JavaScript function.

More Information