Use buttons inside a grid

From pmusers
Jump to: navigation, search

This example shows how to insert buttons inside a grid and then execute custom JavaScript code when those buttons are clicked.


Dynaform: Product List.json (right click and select Save Link As)
Author: Amos Batto (amos@processmaker.com)
Version: 1.0 (2019-01-09)
Tested in: ProcessMaker 3.3.0 Community in Debian 9.5 with Firefox 52


Create the following Dynaform which contains a grid with the ID "productList". In this grid, the user will enter the price and quantity of products and then click a button labeled "Calculate" to multiple the price times the quantity and insert that result in the "Total" field.

GridWhereButtonWillBeInsertedInDesigner.png

The "productList" grid contains the following fields:

  • Text with ID "productName"
  • Text with ID "price"
  • Text with ID "quantity"
  • Text with ID "total"
  • Text with ID "placeholder", where a button will be inserted in its place

Then, add the following JavaScript to the DynaForm:

var gridId = "productList";  //set to ID of grid
var oGrid = $("#"+gridId);

//set to the column number for the fields in the grid:
var columnPrice = 2;
var columnQuantity = 3;
var columnTotal = 4;
var columnButton = 5;

//function to round to a fixed number of decimal digits:
function roundToFixed(_float, _digits){
  var rounder = Math.pow(10, _digits);
  return (Math.round(_float * rounder) / rounder).toFixed(_digits);
}


//function to calcualte the total:
function calculateTotal(rowNo) {
  var price    = parseFloat( oGrid.getValue(rowNo, columnPrice) );
  var quantity = parseInt( oGrid.getValue(rowNo, columnQuantity) );
  var total = '';
  
  if (!isNaN(price) && !isNaN(quantity)) {
    var total = roundToFixed(price * quantity.toFixed(2), 2);
  }
  
  oGrid.setValue(total, rowNo, columnTotal);
}  

//add buttons to existing rows when the Dynaform loads:
var nRows = oGrid.getNumberRows();

for (var i = 1; i <= nRows; i++) {
  var oField = oGrid.getControl(i, columnButton);
  oField.hide();
  
  var sButton = '<button id="form['+gridId+']['+i+'][calculate]" onclick="calculateTotal('+i+');">Calculate</button>';
  oField.parent().append(sButton);
}

//add a button to the new row when it is created:
oGrid.onAddRow( function(aNewRow, oGrd, rowIndex) {
  var oPlaceholder = oGrd.getControl(rowIndex, columnButton);
  oPlaceholder.hide();
  var sButton = '<button name="calculateButton" onclick="calculateTotal('+rowIndex+');">Calculate</button>';
  oPlaceholder.parent().append(sButton);
} );  

//Renumber all the row numbers in the buttons' calculateTotal(rowNo) function call when a row is deleted: 
oGrid.onDeleteRow( function(oGrid, aRow, rowIndex) {
  //add buttons to existing rows when the Dynaform loads:
  var nRows = oGrid.getNumberRows();

  for (var i = 1; i <= nRows; i++) {
    var oButton = oGrid.getControl(i, columnButton).parent().find("button");
    oButton.prop("onclick", 'calculateTotal('+i+');');
  }
} );

Set the variables at the top to the ID of the grid and the column numbers in the grid which hold the "price", "quantity", "total" and "placeholder" fields.

The code contains the calculateTotal() function that will be called when one for the buttons is clicked in order to calculate the total and insert it in the grid. The first parameter of the function is the row number, so that the function knows which row to use when doing the calculation. Another way to get the row number is to use code to examine the other IDs of fields in the same row where the button is located, but that is more complicated.

When the Dynaform loads, this code loops through the existing rows in the grid and hides the "placeholder" text fields. (It is recommended to hide the field and not delete it, because ProcessMaker expects the field to exist when the form is submitted.) Then, the code inserts a button in the parent <div> holding the "placeholder" field. Note that the HTML code for the button does not contain an ID, but one can be added if needing to access the button directly. The button's onclick property is set to: calculateTotal(rowNo);

An event handler is set with grid.onAddRow() to add a button to new rows when they are created in the grid. When a row is deleted from the grid, all the row numbers in the buttons' onclick="calculateTotal(rowNo)" properties will be wrong, so grid.onDeleteRow() is used to execute code which renumbers the row numbers in the buttons'onclick property.

When the Dynaform is used in a case, the user can enter the price and quantity and click on the "Calculate" buttons to insert the total in each row:

CalculateTotalInGridFilledByUser.png