Actions of the client application

To be accurate, a client action is a function that returns an object containing the delta of the application global state changing. When a chain of actions is called (for example, "validate, save, exit"), all actions in it are called one by one. Chages of state, returned by each action, are combined and, once the calling is over, are applied to the global state of the application, which it reacts to.

A list of system actions and their architecture can be found here. User-defined actions are created in a special section of the admin panel. Each form is attributed a file with the actions code. Besides, you can also connect a global actions handler to the application by creating a global variable.

var globalUserActions = {
   actionName : function (ars)
   {
       ....
   },
   ...
}

When a form component calls an event that is assigned a chain of actions, DWKit searches for them by their names. The order of execution is the following (from topmost to lowermost):

  • action defined for the form
  • global user-defined action
  • system action

Thus, you can, for example, redefine or complement the system's 'validate' or any other action.

Input parameters

Each action receives the same set of input parameters as a single object. That's why you can declare actions as function(args) or function({...}) and include the parameters you need in the object. Here is the list of all parameters:

  • data - data displayed in the form, which the action has been called from
  • originalData - original, not edited form data
  • state - global state of the application
  • component - reference to the DWKitForm React component, which the action has been called from
  • formName - name of the form, which the action has been called from
  • index - index of a modal window, if the form is modal
  • controlRef- reference to the control, which the event that has enabled actions has been called in
  • parameters - additional parameters that can be created and edited in the form builder
  • isChild - if true, action has been called from a modal form

Returned values

DWKit makes it possible to return from action depending on your needs either an empty object or a delta of the change of the global state, or a promise for async operations, or to change its data object or terminate the chain of actions with an error.

Empty value

You can implement a certain code in an action without changing the application state. The best solution in this case would be to return an empty object.

actionName : function (ars)
{
    return {};
},

Data changing

Sometimes, you just need to change the data displayed in the form with as least effort as possible. In the example below, a control with the "Property3" name is assigned a value of the sum of controls with names "Property1" and "Property2".

actionName : function ({data})
{
    data.Property3 = data.Property1 + data.Property2;
    return {};
},

Returning delta of the global state

You can return an object that contains only changes of the global state of the application. In the object, you should mention only the fields to be changed. Below is an example of the code that hides or creates the readonly controls in the form.

actionName : function (args)
{
    var hideControls = [];
    hideControls.push("Property1");
    var readOnlyControls = [];
    readOnlyControls.push("Property2");
    return {
        app: {
            form: {
                models: {
                    hideControls: hideControls,
                    readOnlyControls: readOnlyControls
                }
            }
        }
    };
}

The control with the "Property1" name will be hidden, while the control with the "Property2" name will not be available for editing. Using the mechanism of partial changing of the global state, you can get the total control over the entire application.

Returning Promise to execute asynchronous operations

It is better off making asynchronous requests via Promises. You can use fetch to make requests. At the same time, it is necessary to return a function that returns Promise from the action.

actionName : function (args)
{
    return (dispatch) =>
    {
        return fetch('/workflow/execute?' + encodeQueryData(urlData),
        {
            credentials: 'same-origin',
            method: 'post'
        })
        .then(response => response.json())
        .then(response => {
            if (response.success) {
                let msg = "The command execution has been completed!";
                dispatch(appActions.app.resetfetchcount());
                alertify.success(msg);
            }
            else
                dispatch(appActions.app.form.data.save.failure(response.message, response.details));
        })
        .catch(error => {
            dispatch(appActions.app.form.data.save.failure(error.message, error.stack));
        }); 
    }    
}

fetch - returns Promise that will be included in the execution chain. If necessary, you can find more detals on what Promises are here. dispatch is a function, via which Redux-actions are called (they also change the state). It can be used optionally.

Besides, you can return a state delta from a promise to change the application global state.

actionName : function (args)
{
    return () => {
        return fetch('/someurl').then(() => {
            return Promise.resolve({
                stateDelta: {
                    app: { `some state delta` }
                }});
            });
}

Interruption of the execution of a chain of actions

Use throw in order to interrupt execution. For example, this is how the validate action functions. If a form is not valid, throw is called and execution of the chain is interrupted (save and exit do not happen), while the errors are displayed in the form.

actionName : function (args)
{
    var formErrorsDelta = {
        main: {...},
        children: {...}
    };
    throw {
        level: 1,
        message: "Error occurs!",
        formerrors: formErrorsDelta
    };
}

Binding chains of client actions to control events

Binding is taking place in the admin in the form builder on the Events tab. Here, you should specify a chain of actions an event creates, the additional parameters, and, if necessary, a control the event comes from (for example, a button that opens an editing form for a grid, will send an event from the grid).