We hope you'll join us for our 4/23 webinar on using data tables to apply reference ranges and AE codes in OC4. For more information and to register, visit https://register.gotowebinar.com/register/2882170018956684555

Displaying difference in days between two dates in a repeeting group

kristiakkristiak Posts: 1,338 ✭✭✭
On Gerben Rienk's site there is an excellent function to calculate difference in days between two dates. However, when I try the same in a repeating group it does not calculate the days.

Comments

  • Csaba.HalmagyiCsaba.Halmagyi Posts: 54 ✭✭
    edited May 2017
    These functions heavily rely on the OpenClinica page layout. A function that was designed for a repeating grid will not work for a non-repeating group and vice versa.

    Reference to an item in a non-repeating grid looks something like this:
    var fieldDate1 = $("#Date1").parent().parent().find("input");

    Reference to an item in a repeating grid:
    var nameField = inputField.closest('tr').find('td:nth-child('+drugNamePos+') input')

    As you can see tthe approach is different and the script will fail to find the item simply because the item does not exist at the place the script is looking for it.

    What is your usecase exactly? A repeating grid with three fields (date1, date2, input for days)?

    Regards,

    Csaba
  • kristiakkristiak Posts: 1,338 ✭✭✭
    Hi Csaba, I will attach my Excel sheet
  • Csaba.HalmagyiCsaba.Halmagyi Posts: 54 ✭✭
    Allright, give me some time to alter Gerben's function to work with repeating grids.
  • kristiakkristiak Posts: 1,338 ✭✭✭
    Great Csaba! B)
  • Csaba.HalmagyiCsaba.Halmagyi Posts: 54 ✭✭
    edited May 2017
    Hi Krister,

    Please find your modified CRF attached to this post.

    The script I came up with is this:



    jQuery(document).ready(function () {
    var groupName = 'GROUP';
    var date1Pos = 1;
    var date2Pos = 2;
    var daysPos = 3;

    jQuery("table.aka_form_table").on("blur", ":input", function () {
    var inpId = jQuery(this).attr("id");
    if (inpId.indexOf(groupName.toUpperCase()) != -1) {
    updateDays(jQuery(this), date1Pos, date2Pos, daysPos);
    }
    });

    jQuery("table.aka_form_table").on("focus", ":input", function () {
    var inpId = jQuery(this).attr("id");
    if (inpId.indexOf(groupName.toUpperCase()) != -1) {
    updateDays(jQuery(this), date1Pos, date2Pos, daysPos);
    }
    });

    function updateDays(currInp, date1P, date2P, daysP) {
    var date1Field = currInp.closest('tr').find('td:nth-child(' + date1P + ') input.changedField');
    var date2Field = currInp.closest('tr').find('td:nth-child(' + date2P + ') input.changedField');
    var daysField = currInp.closest('tr').find('td:nth-child(' + daysP + ') input');

    var calculatedDifference = DiffInDays(date1Field.val(), date2Field.val());

    if (daysField.val() != calculatedDifference) {
    daysField.val(calculatedDifference);
    daysField.change();
    }
    }

    function OCDateToJDate(OCDate) {

    var dateParts = OCDate.split("-");
    var JDate = new Date(1900, 1, 1);
    JDate.setFullYear(dateParts[2]);
    JDate.setMonth(Calendar._SMN.indexOf(dateParts[1]));
    JDate.setDate(dateParts[0]);
    return JDate;
    }

    function DiffInDays(OCDate1, OCDate2) {

    var msecPerDay = 1000 * 60 * 60 * 24;
    var milliSec1 = OCDateToJDate(OCDate1).getTime();
    var milliSec2 = OCDateToJDate(OCDate2).getTime();
    var interval = milliSec2 - milliSec1;
    var days = Math.round(interval / msecPerDay);
    if (isNaN(days)) {
    return 0;
    }
    else {
    return days;
    }
    }
    });


    This solution is not perfect though as you either have to click in or out of the input field in order to trigger an update action. If @GerbenRienk or anyone else has a better event handling idea, feel free to share it. :)

    I was trying to develop a script as general/customisable as possible.
    The first variable(groupName) holds the name of the group in the CRF, then you have to pass the date field positions in the grid along with the position of the day field.

    Hope this helps.

    Regards,

    Csaba
  • kristiakkristiak Posts: 1,338 ✭✭✭
    Thanks a lot Csaba it works likes magic. I do not think that anyone will complain over having to click on the days field when the system has calculated the number of days for them. As you probably know, I'm not an IT person but just an interested clinical pharmacologist, so I really appreciate any help I can get.
    Best
    Krister
  • GerbenRienkGerbenRienk Posts: 827 ✭✭✭
    edited May 2017
    Great work @Csaba.Halmagyi !
    I've added a little bit to your script:
    <div id="Beacon"></div>
    <script src="includes/jmesa/jquery.min.js"></script>
    <script lang="Javascript">
    $.noConflict();
    jQuery(document).ready(function($){
    var MyTable = $("#Beacon").parent().parent().parent().parent();
    var date1Pos = 1;
    var date2Pos = 2;
    var daysPos = 3;
    var MyTable = $("#Beacon").parent().parent().parent().parent();

    $(MyTable).on("blur", ":input", function() {
    updateDays($(this), date1Pos, date2Pos, daysPos);
    });

    $(MyTable).on("focus", ":input", function() {
    updateDays($(this), date1Pos, date2Pos, daysPos);
    });

    $(MyTable).focusout(function() {
    $('.changedField').each(function() {
    updateDays($(this), date1Pos, date2Pos, daysPos);
    });
    });


    function updateDays(currInp, date1P, date2P, daysP){
    var date1Field = currInp.closest('tr').find('td:nth-child('+date1P+') input:text');
    var date2Field = currInp.closest('tr').find('td:nth-child('+date2P+') input:text');
    var daysField = currInp.closest('tr').find('td:nth-child('+daysP+') input:text');
    var calculatedDifference = DiffInDays(date1Field.val(), date2Field.val());
    if (daysField.val() != calculatedDifference){
    daysField.val(calculatedDifference);
    daysField.change();
    daysField.prop({"readonly":"readonly"});
    }
    }

    function OCDateToJDate(OCDate){

    var dateParts = OCDate.split("-");
    var JDate = new Date(1900,1,1);
    JDate.setFullYear(dateParts[2]);
    JDate.setMonth(Calendar._SMN.indexOf(dateParts[1]));
    JDate.setDate(dateParts[0]);
    return JDate;
    }

    function DiffInDays(OCDate1, OCDate2){
    var msecPerDay = 1000 * 60 *60 *24;
    var mSec1=OCDateToJDate(OCDate1).getTime();
    var mSec2=OCDateToJDate(OCDate2).getTime();
    var days = Math.round((mSec2 - mSec1) / msecPerDay );
    if (isNaN(days)){
    return 0;
    }
    else{
    return days;
    }
    }
    });
    </script>
    As you can see I use a div, which is empty, as a beacon to make a reference to the table. Then we can use this reference for the blur- and focus- events of the inputs, which is what you did.
    These events work fine, as long as you actually give and/or take away the focus to/from an input, as you already stated. However if the user uses the calendar-utility, these events will never be triggered.

    To fix this we add the focusout event of the table as a whole. When this event takes place, we loop through the table and investigate inputs of class changedField and if we find any, we run the calculation. Now the user can open the form, change one or more dates with the calendar-uility and then click Save. Just before the click-save-event is triggered, the focusout is triggered, so the calculations will be up-to-date.

    I also took out the class-selector in function updateDays, because with it the calculation would only be performed if both dates were changed.

    Kind regards,

    Gerben Rienk
    Post edited by GerbenRienk on
  • kristiakkristiak Posts: 1,338 ✭✭✭
    What would I do without you guys. Will you include these instructions on your site?

    Thanks a lot

    Krister
  • Csaba.HalmagyiCsaba.Halmagyi Posts: 54 ✭✭
    Yepp, publishing these scripts on your site is a great idea indeed!
Sign In or Register to comment.