Only select one row in grid

From pmusers
Jump to: navigation, search

This programming example shows how to use JavaScript to only allow one row inside a grid to be selected. The grid has a checkbox which should only be marked in a single row inside the grid. When the checkbox is marked in one row, it will be unmarked in all the other rows in the grid. When the DynaForm is submitted, JavaScript will check that one checkbox is marked. If not, then it will display an error message telling the user to select one row and prevent the form's submit action.


DynaForm: Only select one row in grid.json (right click and select Save link as)
Author: Amos Batto (amos@processmaker.com)
Version: 1.0 (2018-11-19)
Tested in: ProcessMaker 3.2.3 Community in Debian 9.5 with Firefox 52


Create the following DynaForm which contains a grid which contains a list of products where one must be selected to be shipped abroad:

HighlightGridRow-InFormDesigner.png

This DynaForm contains the following fields:

  • A grid with the ID "productsList", which contains the following fields:
    • A checkbox with the ID "shipAbroad". One product must be marked to ship abroad.
    • A textbox with the ID "name" to enter the name of the product,
    • A textbox with the ID "price" to enter the product's price,
    • A textarea with the ID "description" to enter the product's description.
  • A submit button.

Add the following JavaScript code to the DynaForm:

var gridId     = "productsList"; //set to the ID of the grid
var checkboxId = "shipAbroad";   //set to the ID of the checkbox field inside the grid
var checkboxColNo = 0;           //set to the column number of the checkbox (start counting from zero); 

var reGridField = new RegExp("^\\["+gridId+"\\]\\[(\\d+)\\]\\["+checkboxId+"\\]$");
var formId = $("form").prop("id");

$("#"+formId).setOnchange( function(fieldId, newVal, oldVal) {
  var aMatch = fieldId.match(reGridField);
  
  //if the checkbox was marked in the grid, then unmark the checkbox in all other rows in the grid:
  if (aMatch && newVal == '"1"') {
    var selectedRowNo = aMatch[1] - 1; //subtract 1 because start counting grid rows from zero
    var aGridVals = $("#"+gridId).getValue();
    
    //loop through the grid looked for other marked rows:
    for (var i = 0; i < aGridVals.length; i++) {
      
      //if the checkbox in the row is marked and not the currently selected row, then unmark it:
      if (aGridVals[i][checkboxColNo] == '1' && i != selectedRowNo) { 
        //add 1 to row and column numbers because setValue() starts counting from 1, not 0:
        var aGridVals = $("#"+gridId).setValue('0', i+1, checkboxColNo+1);
      }
    }  
  }   
})


//when the form is submitted, make sure that one checkbox in the grid is marked:
$("#"+formId).setOnSubmit( function() {
  var aGridVals = $("#"+gridId).getValue();
  var markedRowNo = null;
    
  //loop through the grid to check that there is one marked checkbox in the grid:
  for (var i = 0; i < aGridVals.length; i++) {
    if (aGridVals[i][checkboxColNo] == '1') {
      if (markedRowNo) {
        alert("Both rows "+markedRowNo+" and "+(i+1)+" cannot be marked. Please only select one.");
        return false; //stop the submit action
      }
      
      markedRowNo = i+1;
    }
   
    if (markedRowNo === null) {
      alert("One row in the grid must be marked in the row.");
      return false;
    }
  }  
})

The code creates a regular expression based on the ID of the grid and the grid's checkbox which is used to determine whether the changed field is a checkbox inside the grid. Remember when dynamically creating regular expressions to use \\ (two backslashes) to escape characters like [ and ] so they will be treated as literals.

The form.setOnChange() method is used to set an event handler which fires when a field's value is changed in the DynaForm. The regular expression in this example will search for a changed field whose ID is "[productsList][N][shipAbroad]" where N is a row number in the grid. If the checkbox has been marked, then its value is '"1"'.

The JavaScript uses grid.getValue() to get an array of the values in the grid and then loops through all the rows in the grid. If it finds another row where the "shipAbroad" checkbox is marked, then it will call grid.setValue() to unmark it.

When the DynaForm is submitted an event handler function set by form.setOnSubmit() will loop through all the rows in the grid and check that only one "shipAbroad" checkbox is marked. If none are marked, then a message is displayed to the user to select one row and the event handler returns false, which stops the submit action.

SelectOneRowInGrid-SelectOneRowMessageWhenSubmitting.png

The user will then have the opportunity to select one row in the grid:

SelectOneRowInGrid-OneRowWasSelected.png