default entries in a repeating item group

For some time we've had the option to insert values in a repeating-item-group, as described on this page, but you may need additional functionality, like making the defaults read-only and/or taking away the option to remove a line in the grid. To be able to do this we must use some java-scripting, so it makes sense to set the defaults in the same script.


fig. 1: the end result

try it for yourself

Do you want to see that on your own OpenClinica? Here is the zip-file.

what does the script do?

The code is put in the header column of the first item of the repeating-item-group and it is not so difficult, in fact it looks a lot like the code that was used to create an autonumber:

<div id="Beacon"></div>
<script src="includes/jmesa/jquery.min.js"></script>
<script lang="Javascript">
$.noConflict();
jQuery(document).ready(function($){
  var valuesToInsert = ["Ig","Hgb","Na","K","pH","ALAT","ASAT","Creat"];
  var columnToInsert = 1;
  var columnWidth = 50;
  //make a reference to the table we're in 
  var MyTable = $("#Beacon").parent().parent().parent().parent();
  //define a counter 
  var i = 0;
  var myInput;
  //define the function
  function setDefaults(){
    //loop through the tr's
    $(MyTable).children('tbody').children('tr').each(function(){
      //make a reference to the right input
      myInput = $(this).children('td:nth-child(' + columnToInsert + ')').children('input:text');
      //check if the input is already populated
      if(valuesToInsert[i] && myInput.val() != valuesToInsert[i]){
        myInput.val(valuesToInsert[i]);
        myInput.change();
      }
        myInput.attr("readonly","readonly");
        myInput.width(columnWidth);
      //increase the counter 
      i++;
    });
  }
  //now call the function
  window.setTimeout(function(){
      setDefaults();
    },1);
});
</script>

First we define a div that will act as a Beacon and we call it Beacon. From this beacon we can refer to the table of the repeating-item-group as the parent of the parent of the parent of our parent:
MyTable = $("#Beacon").parent().parent().parent().parent().
To keep things simple we define the values to insert plus the column in which to insert and also the width of the inputs we will use:
valuesToInsert = ["Ig","Hgb","Na","K","pH","ALAT","ASAT","Creat"]
var columnToInsert = 1
var columnWidth = 50

function setDefaults() is where it's happening: we loop through all the table-rows, and in each table-row we take the first n-th child of type td, whatever we defined as the column to insert.
Once we're there, we can check if the value has already been inserted and if not, we do that and set the status to changed.
And to round things up we make the input read-only and set the width.

There's one more thing that needs explaining and that is window.setTimeout(function(){setDefaults();},1);. This function waits one millisecond and then executes the function and the thing is: it starts counting once the whole page has finished. "Mmmh, that sounds like document-ready and we already use that" you may say and yes, we do, but a grid in OpenClinica is built with the so-called repetition-model which makes one line of the grid and then copies it. JQuery doesn't wait for that, so your grid could be halfway, when jQuery tries to populate it. With setTimeout we wait for the repetition-script to finish and one millisecond later we start populating.

now tell us what animals you saw in Australia

After taking so much trouble to insert the defaults you may want prevent the users from deleting the rows. This can be done relatively easy, because the remove-icons all share the same class, called button_remove. Here you see the result:


fig. 2: CRF with remove-icons gone

The code is almost similar to the previous code:

<div id="BeaconAnimal"></div>
<script src="includes/jmesa/jquery.min.js"></script>
<script lang="Javascript">
$.noConflict();
jQuery(document).ready(function($){
  var valuesToInsert = ["whale", "wombat", "wallaby"];
  var columnToInsert = 1;
  var columnWidth = 80;
  //make a reference to the table we're in 
  var MyTable = $("#BeaconAnimal").parent().parent().parent().parent();
  //define a counter 
  var i = 0;
  var myInput;
  //define the function
  function setDefaults(){
    //loop through the tr's
    $(MyTable).children('tbody').children('tr').each(function(){
      //make a reference to the right input
      myInput = $(this).children('td:nth-child(' + columnToInsert + ')').children('input:text');
      //check if the input is already populated
      if(valuesToInsert[i] && myInput.val() != valuesToInsert[i]){
        myInput.val(valuesToInsert[i]);
        myInput.change();
      }
        myInput.attr("readonly","readonly");
        myInput.width(columnWidth);
      //increase the counter 
      i++;
    });
    // now remove the remove buttons that are all of class button_remove
    $(MyTable).find(".button_remove").remove();
  }
  //now call the function
  window.setTimeout(function(){
    setDefaults();
  },1);
});
</script>

The difference is just one line, $(MyTable).find(".button_remove").remove(), that takes our table and removes from it all objects of class button_remove.
You may think "can't we just do that for the whole form, as opposed to one table?" but it could be that you have on the same section more than one grid and then you would like to apply the remove-action just on one.


fig. 3: where to put it

Other how-to-pages can be found here.

this page was last reviewed February 2018