Skip to main content

Global state of the client application

DWKit application client logic is based on changes of the application global state and reaction of the React components to the changes. Reaction of the components usually includes re-rendering. Architecturally, all the information to be accessed or changed is located in the global state. State is a large JavaScript object of a complex structure. Let's take a look at what its parts are responsible for.

const state = {
app: {
user: null,
impersonatedUserId: null,
fetchCount: 0,
error: undefined,
errorDetails: undefined,
form: {
models: {
model: null, // main form model
mapping: null, // main mapping (use for modal forms)
hideControls: null,
readOnlyControls: null,
readOnly: null
},
filters: {
main: null // grid1 : {column: 'columnName', value: value, term: 'like'}
},
data: {
isDirty: false,
isNew: false, // false if this data were obtained from the server
original: null,
modified: null
},
errors: null,
formParams: {
schemes: null,
securityGroup: undefined,
permissions: null,
name: null
}
},
modals: {
models: {}, /* models[formName] == // {model, mapping, formParams} */
windows: {}, /* windows[formName_index] == {
id: null,
parentId: null,
type: 'form', //or 'flow'
viewType: 'modal', //or 'sidebar'
filters: null, // hash map
data: null, // {isDirty: isDirty, original: original, modified: modified, filter: {}, property: ""}
errors: null,
name: null // name from modals list,
onOpenFunc: null,
onCloseFunc: null,
selectedScheme: null,
hideControls,
readOnlyControls,
readOnly,
keyIndex: null
}*/
order: [] // order of modal windows
}
},
router:
{
history: null,
redirect: null,
location: null,
push: null,
filter: null
},
settings: {
backendUrl: "", // "https://domain.com"
fetchOptions: undefined,
form: "form",
flow: "flow",
accountget: "/account/get",
uiform: "/ui/form",
uiflow: "/ui/flow",
dataget: "/data/get",
datachange: "/data/change",
datadelete: "/data/delete",
datadictionary: "/data/dictionary",
dataupload: '/data/upload/',
datadownload: '/data/download/',
dataexport: '/data/export',
workflowget: "/workflow/get",
workflowexecute: "/workflow/execute",
workflowset: "/workflow/set",
notificationhub: "/hubs/notifications",
executeaction: "/actions/execute"
}
};
  • state.app.user - object containing information on the current authorized user. For example:

    {
    id: '540e514c-911f-4a03-ac90-c450c28838c5',
    name: 'admin',
    email: '',
    isLocked: false,
    roles: ['Admins'],
    groups: [],
    timezone: null,
    localization: null
    }
  • state.app.impersonatedUserId - id of a user, on behalf of whom an authorized user is executing operations.

  • state.app.fetchCount - counter of asynchronous requests; when it is > 0, screen is disabled and a progress bar is displayed.

  • state.app.error and state.app.errorDetails - text and stack trace of the last application error.

Main form object

You can find everything required for DWKit main form in the state.app.form object.

  • Everything to display form layouts is in the state.app.form.models object.
    • state.app.form.models.model - main form layout (model).
    • state.app.form.models.mapping - support object of converting data fields names in the form into data fields names in the database. Used to synchronize data between parent and modal windows.
    • state.app.form.models.hideControls - list of names of controls that should be hidden in the form.
    • state.app.form.models.readOnlyControls - list of names of controls that should be converted into readonly state in the form.
    • state.app.form.models.readOnly - if set to true, entire form will be in the readonly state.
  • state.app.form.filters object stores filters for collection components.
  • state.app.form.data stores data displayed in the form.
    • state.app.form.data.original - original data of the main form, obtained from server.
    • state.app.form.data.modified - modified data of the main form. They coincide with those displayed in the form.
    • state.app.form.data.isDirty - if true, data is modified compared to those having come from the server.
    • state.app.form.data.isNew - if true, data is absent on server
  • state.app.form.errors object contains validation errors in the form. Errors object has the following format.
state.app.form.errors = {
main: {
plainFormField1: "Error message", // it is an error with a message
plainFormField2: true, // it is an error without a message
collectionFormField: [ // an error in some row in a collection
{
_id: "bb622fb9-d057-44ab-a1d1-a6ae242e286f", // row id
collectionColumn1: "Error message", // it is an error in a collection row with a message
collectionColumn2: true // it is an error in a collection row without a message
}
]
}
}
  • state.app.form.formParams contains additional form parameters, uploaded from server.
    • state.app.form.formParams.schemes - names of workflow engine schemes associated with the form.
    • state.app.form.formParams.securityGroup - name of a group associated with the form.
    • state.app.form.formParams.permissions - form permissions.
    • state.app.form.formParams.name - form name.

Modal windows store their states in the state.app.modals object.

  • state.app.modals.models object contains layouts of all opened modal forms. Actually this is cache, so that similar modal windows could be opened without layout being constantly requested. You can get access to 'FormName' form layout using the state.app.modals.models['FormName'] indexer. This object structure includes the following:
    • state.app.modals.models['FormName'].model - layout (model) of the form.
    • state.app.modals.models['FormName'].mapping - a support object of converting names of the data fields in a form into names of the data fields in a database. Used to synchronize data between the parent and modal windows.
    • state.app.modals.models['FormName'].formParams - contains additional form parameters: schemes, securityGroup, permissions, name.
  • state.app.modals.windows contains data of opened modal windows. Each window has its string ID: 'FormName_index', where index is a number >= 0, defining opened window level with respect to the main form. For example, it will be 'FormName_0' for the first opened modal form. You can get access to 'FormName_0' form layout using the state.app.modals.windows['FormName_0'] indexer. This object structure includes the following:
    • state.app.modals.windows['FormName_0'].id - window ID, i.e. "FormName_0".
    • state.app.modals.windows['FormName_0'].parentId - parent window ID. It is filled in if the modal window was opened out of another modal window.
    • state.app.modals.windows['FormName_0'].type - 'form' or 'flow' depending what modal window contains - a form or business flow.
    • state.app.modals.windows['FormName_0'].viewType - 'modal' or 'sidebar' - modal window display type.
    • state.app.modals.windows['FormName_0'].filters - stores filters for collection components.
    • state.app.modals.windows['FormName_0'].data - data displayed in window.
    • state.app.modals.windows['FormName_0'].data.original - original data, obtained from server.
    • state.app.modals.windows['FormName_0'].data.modified - modified data. They coincide with those displayed in modal window.
    • state.app.modals.windows['FormName_0'].data.isDirty - if true, data is modified compared to those having come from server.
    • state.app.modals.windows['FormName_0'].data.isNew - if true, data is absent on server.
    • state.app.modals.windows['FormName_0'].data.filter - filter (or just entity ID) with which modal window was opened.
    • state.app.modals.windows['FormName_0'].data.property - if modal window was opened from grid, this grid Name will be displayed here.
    • state.app.modals.windows['FormName_0'].errors - contains validation errors displayed in modal window.
    • state.app.modals.windows['FormName_0'].name - form name - 'FormName', opened in modal window.
    • state.app.modals.windows['FormName_0'].onOpenFunc - an additional function called when opening a modal window.
    • state.app.modals.windows['FormName_0'].onCloseFunc - an additional function called when closing a modal window.
    • state.app.modals.windows['FormName_0'].hideControls - list of control names that should be hidden.
    • state.app.modals.windows['FormName_0'].readOnlyControls - list of control names that should be converted into the readonly state.
    • state.app.modals.windows['FormName_0'].readOnly - if set to true, entire form will be in the readonly state.
    • state.app.modals.windows['FormName_0'].keyIndex - number >= 0, defining opened window level with respect to the main form. For example, the first opened modal form will have 0.
  • state.app.modals.order object stores modal windows display order. This is the array of modal windows IDs. The smaller index is, the closer the window is to the root form. For example, ['FormName_0', 'AnotherFormName_1'].

Routing parameters

You can find parameters which control transitions between "pages" of your application in the state.router object.

  • state.router.location - current location - address of a displayed page. This is an object of the following type:

    state.router.location = {
    pathname: '/form/DocumentEdit/b12a546c-e193-4ad5-a5c7-d31de7f7907e/',
    search: '',
    hash: '',
    key: '2xkl9d'
    },
  • state.router.push - if you write an url in this part of the application state, it will be displayed in the browser address bar, and all components dependent on the url will be redrawn. Location will also be updated.

  • state.router.refresh - if you write any value (for example, the "refresh" line) in this part of the state application, current page will be redrawn.

Settings

You can find different application settings in the state.settings object. Mainly, these URLs by which DWKit client-side requests DWKit controllers.

Global state customization

You can add your own section into global state, which will then influence your application. You don't need to change JavaScript code to do that. There are three mechanisms which allow you to add custom section into the global state:

To display state, you can use StateBindedForm component. In our demo example, document counters (inbox, outbox, total) are stored in a special section of the global state:

state.app.extra = {
inbox: 2,
outbox: 16,
doccount: 20
}

They get there via our SignalR interaction mechanism and are displayed by the component bound to this section of the global state.

<StateBindedForm className="dwkit-sidebar-container" {...sectorprops} formName="sidebar"
stateDataPath="app.extra" data={{currentEmployee: currentEmployee}}
modelurl="/ui/form/sidebar"/>

Please note, that global state side displayed by stateDataPath="app.extra" component is specified in <StateBindedForm/> component settings.