View source | Discuss this page | Page history | Printable version   
Toolbox
Main Page
Upload file
What links here
Recent changes
Help

PDF Books
Add page
Show collection (0 pages)
Collections help

Search

How to create client event handler actions

Contents

Introduction

This howto discusses how to implement client side (javascript) functions which are executed before or after an event fired on a standard window of the User Interface.

Bulbgraph.png   This feature is available from version 3.0PR16Q4

Example Module

This howto is supported by an example module which shows examples of the code shown and discussed.

The code of the example module can be downloaded from this mercurial repository: https://code.openbravo.com/erp/mods/org.openbravo.platform.ci/

Defining Client Event Handler Actions

A client event handler action is a function in javascript available through a global ID. The global ID should be unique, it is strongly adviced to use the module's db prefix. The action has to be defined in a javascript file located in the module, see here for information on howto add javascript code to Openbravo.

The following is an example of this kind of actions: it shows a message after saving a record. The message type and content depends on if we are creating or updating the record.

 
OB.OBPFCI = {};
OB.OBPFCI.ClientSideEventHandlers = {};
OB.OBPFCI.PRODUCT_CATEGORY_HEADER_TAB = '189';
 
OB.OBPFCI.ClientSideEventHandlers.showMessage = function (view, form, grid, extraParameters, actions) {
  var data = extraParameters.data;
 
  view.messageBar.keepOnAutomaticRefresh = true;
  if (extraParameters.isNewRecord) {
    // Save flow
    view.messageBar.setMessage(isc.OBMessageBar.TYPE_SUCCESS, 'New Record', 'Created Product Category with name ' + data.name);
  } else {
    // Update flow
    view.messageBar.setMessage(isc.OBMessageBar.TYPE_INFO, 'Updated Record', 'Updated Product Category with name ' + data.name);
  }
  OB.EventHandlerRegistry.callbackExecutor(view, form, grid, extraParameters, actions);
};
 
OB.EventHandlerRegistry.register(OB.OBPFCI.PRODUCT_CATEGORY_HEADER_TAB, OB.EventHandlerRegistry.POSTSAVE, OB.OBPFCI.ClientSideEventHandlers.showMessage, 'OBPFCI_ShowMessage');

As you can see the action is placed in a global object, in this case the module's dbprefix is used for that. It is important to note that you should not use var before the global object definition, otherwise your var is not global. This is because the global javascript code included in Openbravo is in fact executed within a function.

This kind of actions receive 5 arguments:

Bulbgraph.png   Each action is responsible of invoking OB.EventHandlerRegistry.callbackExecutor. If an action does not call it, the subsequent actions (if any) will not be executed.

Registering, setting an Action for an Event within a Tab

A client event handler action is linked to an event launched in a particular tab. This link is created by registering the action programmatically. Thus, it is possible to:

A client event handler action is registered through the OB.EventHandlerRegistry.register method. It expects 4 parameters:

OB.EventHandlerRegistry.register(OB.OBPFCI.PRODUCT_CATEGORY_HEADER_TAB, OB.EventHandlerRegistry.POSTSAVE, OB.OBPFCI.ClientSideEventHandlers.showMessage, 'OBPFCI_ShowMessage');

Some comments about this code:

The event types currently supported are:

In the case of PRESAVE and POSTSAVE the extraParameters argument will contain the following information:

In the case of PREDELETE the extraParameters argument will contain the following information:

Multiple Actions Functions per Event, Call Order

The client event handler actions can have a sort property to control the call-order if there are multiple actions for one event in the same tab.

It is for example set like this:

OB.OBPFCI.ClientSideEventHandlers.showMessage.sort = 20;

Actions with a lower sort value will be executed before actions with a higher one. If an action does not have a sort defined it gets the sort 100 by default.

Overriding/Replacing an Action

An action can be registered using an id (action id). If there is already an action registered with the same id for the same tab and event type then it is replaced by the new registration.

Examples

Post-save Action: Open a Tab

The following example shows how to open a new tab after saving a record.

 
OB.OBPFCI.PRODUCT_HEADER_TAB = '180';
OB.OBPFCI.ClientSideEventHandlers.openTab = function (view, form, grid, extraParameters, actions) {
  if (extraParameters.isNewRecord) {
    // Save flow
    OB.Utilities.openDirectTab(OB.OBPFCI.PRODUCT_HEADER_TAB);
  }
  OB.EventHandlerRegistry.callbackExecutor(view, form, grid, extraParameters, actions);
};
 
OB.OBPFCI.ClientSideEventHandlers.openTab.sort = 120;
OB.EventHandlerRegistry.register(OB.OBPFCI.PRODUCT_CATEGORY_HEADER_TAB, OB.EventHandlerRegistry.POSTSAVE, OB.OBPFCI.ClientSideEventHandlers.openTab, 'OBPFCI_OpenTab');

In this case we are opening the Product window after creating a new Product Category. We use extraParameters.isNewRecord to identify the save flow. Finally we are invoking OB.EventHandlerRegistry.callbackExecutor to ensure the execution of the subsequent actions. In addition, we are giving a sort number of 120.

Post-save Action: Refresh the Grid

The following example shows how to refresh the grid after saving or updating a record.

 
OB.OBPFCI.COUNTRY_HEADER_TAB = '135';
OB.OBPFCI.ClientSideEventHandlers.refreshGrid = function (view, form, grid, extraParameters, actions) {
  var viewInGridMode = !view.isShowingForm,
      callback;
 
  callback = function () {
    OB.EventHandlerRegistry.callbackExecutor(view, form, grid, extraParameters, actions);
  };
 
  if (viewInGridMode) {
    grid.refreshGridFromClientEventHandler(callback);
  }
};
 
OB.EventHandlerRegistry.register(OB.OBPFCI.COUNTRY_HEADER_TAB, OB.EventHandlerRegistry.POSTSAVE, OB.OBPFCI.ClientSideEventHandlers.refreshGrid, 'OBPFCI_RefreshGrid');

Note that we are making use of a function of the grid called refreshGridFromClientEventHandler, that is a special grid refresh method adapted to be used within this type of actions.

This way, we are forcing the grid in the header of the Country and Region window to be refreshed every time a new record is created/updated on it by using the grid view.

Pre-save Action: Client Validation

In this example, we are checking a user's e-mail before saving/updating a record.

 
OB.OBPFCI.USER_HEADER_TAB = '118';
OB.OBPFCI.ClientSideEventHandlers.validateEmail = function (view, form, grid, extraParameters, actions) {
  var data = extraParameters.data,
      emailPattern = /^\w+([\.\-]?\w+)*@\w+([\.\-]?\w+)*(\.\w{2,3})+$/;
 
  if (data.email && !emailPattern.test(data.email)) {
    view.messageBar.setMessage(isc.OBMessageBar.TYPE_ERROR, 'Invalid Email', 'The email address ' + data.email + ' is not valid');
    return; // Interrupting save action: not calling OB.EventHandlerRegistry.callbackExecutor
  }
  OB.EventHandlerRegistry.callbackExecutor(view, form, grid, extraParameters, actions);
};
 
OB.EventHandlerRegistry.register(OB.OBPFCI.USER_HEADER_TAB, OB.EventHandlerRegistry.PRESAVE, OB.OBPFCI.ClientSideEventHandlers.validateEmail, 'OBPFCI_ValidateEmail');

Note that if the e-mail is not valid, we do not call OB.EventHandlerRegistry.callbackExecutor so the save operation will not be performed.

Pre-save Action: Calling Server Side

In this case we are going to call a server side action before saving a Goods Shipment line. To understand this example is important to know the concept of Action Handler.

 
OB.OBPFCI.GOODS_SHIPMENT_LINES_TAB = '258';
OB.OBPFCI.ClientSideEventHandlers.checkStorageBin = function (view, form, grid, extraParameters, actions) {
  var data = extraParameters.data,
      callback, storageBin;
 
  if (data.storageBin) {
    storageBin = data.storageBin;
  }
 
  callback = function (response, cdata, request) {
    var row, stack, level;
    if (cdata && cdata.storageBinInfo) {
      row = cdata.storageBinInfo.row;
      stack = cdata.storageBinInfo.stack;
      level = cdata.storageBinInfo.level;
      if (row !== '0') {
        view.messageBar.setMessage(isc.OBMessageBar.TYPE_ERROR, 'Invalid Storage Bin', 'Only storage bins with Row 0 are allowed');
        return; // Interrupting save action: not calling OB.EventHandlerRegistry.callbackExecutor
      }
      view.messageBar.setMessage(isc.OBMessageBar.TYPE_INFO, 'Shipment Line Saved', 'Storage Bin Info: Row ' + row + ', Stack ' + stack + ', Level ' + level);
      OB.EventHandlerRegistry.callbackExecutor(view, form, grid, extraParameters, actions);
    }
  };
 
  // Calling action handler
  OB.RemoteCallManager.call('org.openbravo.platform.ci.actionhandler.GoodsShipmentLinesActionHandler', {
    storageBinId: storageBin
  }, {}, callback);
 
};
 
OB.EventHandlerRegistry.register(OB.OBPFCI.GOODS_SHIPMENT_LINES_TAB, OB.EventHandlerRegistry.PRESAVE, OB.OBPFCI.ClientSideEventHandlers.checkStorageBin, 'OBPFCI_CheckStorageBin');

The above example calls to GoodsShipmentLinesActionHandler. This action handler returns the row, stack and level of the storage bin whose id has been sent in the request. This id has been retrieved from the goods shipment line that we are about to save.

The record will not be saved if the storage bin row is not 0. Otherwise, we show a message with the storage bin information.

Pre-delete Action: Client Validation

In this case we are going to call a server side action before deleting a Sales Order line. As in the previous example, to understand this one is important to know the concept of Action Handler.

 
OB.CancelAndReplace.ClientSideEventHandlersPreDelete.showMessage = function (view, form, grid, extraParameters, actions) {
  var selectedRecords = extraParameters.recordsToDelete,
      record, replacementRecords = [],
      record, deliveredQuantity;
 
  view.messageBar.keepOnAutomaticRefresh = true;
 
  callback = function (response, cdata, request) {
    for (i = 0; i < cdata.result.length; i++) {
      record = cdata.result[i].record;
      deliveredQuantity = cdata.result[i].deliveredQuantity;
      if (deliveredQuantity !== 0) {
        var msgInfo = [];
        msgInfo.push(record.lineNo);
        msgInfo.push(record.product$_identifier);
        view.messageBar.setMessage(isc.OBMessageBar.TYPE_ERROR, null, OB.I18N.getLabel('CannotDeleteLineWithDeliveredQtyInReplacementLine', msgInfo));
        return;
      }
    }
    OB.EventHandlerRegistry.callbackExecutor(view, form, grid, extraParameters, actions);
  };
 
  if (view.getParentRecord().documentStatus === 'TMP') {
    for (i = 0; i < selectedRecords.length; i++) {
      record = selectedRecords[i];
      if (record.replacedorderline) {
        replacementRecords.push(record);
      }
    }
 
    if (replacementRecords.length) {
      //Calling action handler
      OB.RemoteCallManager.call('org.openbravo.common.actionhandler.CancelAndReplaceGetCancelledOrderLine', {
        records: replacementRecords
      }, {}, callback);
    } else {
      OB.EventHandlerRegistry.callbackExecutor(view, form, grid, extraParameters, actions);
    }
  } else {
    OB.EventHandlerRegistry.callbackExecutor(view, form, grid, extraParameters, actions);
  }
};
 
OB.EventHandlerRegistry.register(OB.CancelAndReplace.SALES_ORDERLINES_TAB, OB.EventHandlerRegistry.PREDELETE, OB.CancelAndReplace.ClientSideEventHandlersPreDelete.showMessage, 'OBCancelAndReplace_ShowMessage');

Retrieved from "http://wiki.openbravo.com/wiki/How_to_create_client_event_handler_actions"

This page has been accessed 500 times. This page was last modified on 26 September 2016, at 09:27. Content is available under Creative Commons Attribution-ShareAlike 2.5 Spain License.