OpenSpecimen allows configuring calculated fields to be displayed on overview pages.
It is not possible to use ‘Form’ fields as inputs when creating a calculated fields.
Example 1: Display participant concatenated first name and last name Click here to view details...
{
"name": "calcCpr.name",
"displayExpr": "cpr.participant.firstName + ' ' + cpr.participant.lastName",
"caption": "Name",
"type": "span"
} A more robust example of the above is no blank space when either first name or last name is not specified.
{
"name": "calcCpr.name",
"displayExpr": "fns.concat(cpr.participant.firstName, cpr.participant.lastName)",
"caption": "Name",
"type": "span"
}
Example 2: Display Visit Clinical Diagnosis Values concatenated with their Concept code Click here to view details...
{
"name": "calcVisit.diagnosisList",
"caption": "Clinical Diagnosis",
"type": "span",
"displayExpr": "fns.concatList(visit.diagnosisList, '!!value && value != \"Not Specified\" ? value + (!!conceptCode ? \" (\" + conceptCode + \")\" : \"\") : \"\"', ', ')"
}
Example 3: Display age as of today Click here to view details...
{
"name": "calcCpr.birthDate",
"displayExpr": "fns.dateDiffInYears(cpr.participant.birthDate, fns.now()) + ' years'",
"caption": "Age",
"type": "span"
}
Example 4: Display age at the time of visit Click here to view details...
{
"name": "calcVisit.age",
"displayExpr": "fns.ifNotNull(cpr.participant.birthDate, fns.dateDiffInYears(cpr.participant.birthDate, visit.visitDate) + ' years', 'Not Applicable')",
"caption": "Age at the time of Visit",
"type": "span"
}
Example 5: Display age at the time of specimen creation Click here to view details...
{
"name": "calcSpecimen.age",
"displayExpr": "fns.ifNotNull(cpr.participant.birthDate, fns.dateDiffInYears(cpr.participant.birthDate, specimen.createdOn) + ' years', 'Not Applicable')",
"caption": "Age at collection",
"type": "span"
}
Example 6: Display the multiplication of 2 Custom fields Click here to view details...
{
"name": "calcSpecimen.concentration",
"displayExpr": "fns.ifNotNull(specimen.extensionDetail.attrsMap.wbc && specimen.extensionDetail.attrsMap.volsus,(specimen.extensionDetail.attrsMap.wbc * specimen.extensionDetail.attrsMap.volsus).toFixed(2),'Not Specified')",
"caption": "Total WBC Count (10^6)",
"type": "span"
},
Example 7: Adding 2 Number fields Click here to view details...
{
"name" : "calcCpr.NumbersAddition",
"displayExpr" : "fns.ifNotNull(cpr.participant.extensionDetail.attrsMap.number_field_1 && cpr.participant.extensionDetail.attrsMap.number_field_2,+cpr.participant.extensionDetail.attrsMap.number_field_1 + +cpr.participant.extensionDetail.attrsMap.number_field_2, 'Not Specified')",
"caption" : "Sum of Numbers",
"type" : "span"
}
Example 8: Average of 2 Number fields Click here to view details...
{
"name" : "calcCpr.numberFieldAverage",
"displayExpr" : "fns.ifNotNull(cpr.participant.extensionDetail.attrsMap.number_field_1 && cpr.participant.extensionDetail.attrsMap.number_field_2,((+cpr.participant.extensionDetail.attrsMap.number_field_1 + +cpr.participant.extensionDetail.attrsMap.number_field_2)/2), 'Not Specified')",
"caption" : "Number fields Average",
"type" : "span"
}
Example 9: Return the array of substring and display it on child specimen overview page Click here to view details...
{
"name": "calcSpecimen.parentLabel",
"displayExpr": "fns.split(specimen.parentLabel, ':')[0]",
"caption": "Part-Subpart",
"type": "span"
}
Example 10: Display quantity (ug) field on the specimen overview page Click here to view details...
Note: If one of the fields is left blank, the calculated value would be '0' since this is a multiplication field.
{
"name": "calcSpecimen.volume",
"displayExpr": "(specimen.initialQty * specimen.concentration) / 1000",
"caption": "Quantity(ug)",
"type": "span"
}
Example 11: Display if the patient consented or not based on consent responses Click here to view details...
{
"name" : "consents.non_existing", // To avoid unnecessary check for participant with no consents to display.
"type" : "span",
"caption" : "Will never be displayed",
"showInOverviewIf" : "1 == 0"
}, {
"name" : "calcCpr.validConsent",
"caption" : "Valid Consent?",
"type" : "span",
"displayExpr" : "consents != null ? (consents.VCB001 != null ? 'Yes' : 'No') : '###'"
},
Example 12: Display BMI of participant Click here to view details...
{
"name" : "calcCpr.bmi",
"displayExpr" : "+cpr.participant.extensionDetail.attrsMap.weight_kg > 0 && +cpr.participant.extensionDetail.attrsMap.height_kg > 0 ? cpr.participant.extensionDetail.attrsMap.weight_kg / (cpr.participant.extensionDetail.attrsMap.height_kg *2 ) : 'NA'",
"caption" : "BMI",
"type" : "span"
}
Example 13: Display Participant custom field on Visit/Specimen Overview Page as Read-Only Click here to view details...
...
},
{
"name" : "calcVisit.partComment",
"displayExpr" : "fns.ifNotNull(cpr.participant.extensionDetail.attrsMap.comments, cpr.participant.extensionDetail.attrsMap.comments, 'Not-Specified')",
"caption" : "Participant Custom Field (Participant Comments)",
"type" : "span"
},
...
...
...
{
"name" : "calcSpecimen.partComment",
"displayExpr" : "fns.ifNotNull(cpr.participant.extensionDetail.attrsMap.comments, cpr.participant.extensionDetail.attrsMap.comments, 'Not-Specified')",
"caption" : "Participant Custom Field (Participant Comments)",
"type" : "span"
},
... Participant Overview Page
Visit Overview Page
Specimen Overview Page
Example 14: Display Participant Yes/No and Date custom field on Specimen Overview Page as Read-Only Click here to view details...
...
,
{
"name" : "calcSpecimen.partGenetic Testing Decline",
"displayExpr": "cpr.participant.extensionDetail.attrsMap.genetic_testing_decline_02a != null ? ((cpr.participant.extensionDetail.attrsMap.genetic_testing_decline_02a == 1)?'Yes':'No') : 'No'",
"caption" : "Genetic Testing Decline",
"type" : "span"
},
...
...
...
{
"name" : "calcSpecimen.partWithdrawal Date",
"displayExpr" : "fns.ifNotNull(fns.toDateStr(cpr.participant.extensionDetail.attrsMap.withdrawal_date), fns.toDateStr(cpr.participant.extensionDetail.attrsMap.withdrawal_date), 'Not-Specified')",
"caption" : "Withdrawal Date",
"type" : "span"
}
,
... Participant Overview Page
Specimen Overview Page
Example 15: Display Visit default field on Specimen Overview Page as Read-Only Click here to view details...
{
"name" : "calcSpecimen.visitName",
"displayExpr" : "fns.ifNotNull(visit.name, visit.name, 'Not-Specified')",
"caption" : "Visit Name",
"type" : "span"
} Visit Overview Page
Specimen Overview Page
Example 16: Display Visit custom field on Specimen Overview Page as Read-Only Click here to view details...
{
"name" : "calcSpecimen.visitAnatomicalSiteCode",
"displayExpr" : "fns.ifNotNull(visit.extensionDetail.attrsMap.site_code, visit.extensionDetail.attrsMap.site_code, 'Not-Specified')",
"caption" : "Visit Custom Field (Anatomical Site Code) as Read-Only",
"type" : "span"
} Visit Overview Page
Specimen Overview Page
Example 17: Display age as of today in Months Click here to view details...
{
"name": "calcCpr.birthDate",
"displayExpr": "(fns.dateDiffInDays(cpr.participant.birthDate, fns.now()) * 12 / 365).toFixed(0)+ ' months'",
"caption": "Age",
"type": "span"
},
Example 18: Calculating the months remaining after counting the completed years Click here to view details...
{
"name": "calcCpr.birthDate",
"displayExpr": "(fns.dateDiffInDays(cpr.participant.birthDate, fns.now()) / 365 * 12 -fns.ageInYears(cpr.participant.birthDate, fns.now()) * 12).toFixed(0) + ' months'",
"caption": "Age",
"type": "span"
},
Example 19: Calculating the Cohort field based on the consent signature date. Click here to view details...
"name" : "calcCpr.cohort",
"displayExpr" : "consents.consentSignatureDate > 1502841600000 && consents.consentSignatureDate < 1582588800000 ? 'Cohort 1' : (consents.consentSignatureDate > 1582675200000 && consents.consentSignatureDate < 1672531200000 ? 'Cohort 2' : (consents.consentSignatureDate > 1672617600000 ? 'Cohort 3' : 'Unknown'))",
"caption" : "Cohort",
"type" : "span"
}
Example 20: Calculating the Field based on Custom Number field divided by user input value. Click here to view details...
{
"name" : "calcSpecimen.numberField",
"displayExpr" : "fns.ifNotNull(specimen.extensionDetail.attrsMap.number1,((+specimen.extensionDetail.attrsMap.number1)/100), 'Not Specified')",
"caption" : "Divided Cal Field",
"type" : "span"
},
Example 21: Calculating Age of Dead participants and alive participants. Click here to view details...
{
"name" : "calcCpr.age",
"displayExpr" : "fns.ifNotNull(cpr.participant.deathDate, fns.dateDiffInYears(cpr.participant.birthDate, cpr.participant.deathDate) + ' years', fns.dateDiffInYears(cpr.participant.birthDate, fns.now()) + ' years')",
"caption" : "Age",
"type" : "span"
}
#1. If the participant is dead, then it calculates the Age from DOB to Date of death.
#2. If the participant is alive then it calculates the Age from DOB to Current Date.
Inbuilt Functions Click here to view details...
Note: Currently, only collection and received event fields can be used for calculated fields. Fields of other events cannot be used.
fns.ifNull(cond, 'truthValue', 'falseValue')
Returns truthValue when 'cond' is evaluated to either null or undefined. Otherwise, it returns falseValue.
fns.ifNotNull(cond, 'truthValue', 'falseValue')
Returns truthValue when 'cond' is evaluated to non-null or a defined value. Otherwise, it returns falseValue.
fns.concatList(coll, expr, separator)
Concatenates the elements of the collection 'coll' and joins them using the input 'separator'. e.g. fns.concatList(persons, "\'firstName\' + ' ' + \'lastName\'", ",") yields Virat Kohli, Dhanraj Pillay, Atul Bedade
fns.concat(varargs)
Concatenates input arguments using the separator ' '
fns.minValue(coll, expr)
Returns the min value of the 'expr' in the input collection 'coll'
fns.toDateStr(dateObj, [fmt])
Returns date string in locale format or requested format 'fmt'
fns.toDateTimeStr(dateObj, [fmt])
Returns date-time string in locale format or requested format 'fmt'
fns.now() fns.currentTime()
Returns current time in number of milliseconds elapsed since Epoch.
fns.dateDiffInYears(d1, d2)
Returns the number of completed years between d1 and d2.
fns.ageInYears(d1)
Convenience function, which is equivalent to fns.dateDiffInYears(d1, fns.now())
fns.dateDiffInDays(d1, d2)
Returns the number of completed days between d1 and d2.
fns.dateDiffInMinutes(d1, d2)
Returns the number of minutes elapsed between d1 and d2 where d1 < d2
fns.dateDiffInSeconds(d1, d2)
Returns the number of seconds elapsed between d1 and d2 where d1 < d2
fns.split(str, regex)
Returns an array of substrings that are delimited by the regex in the input string.
fns.join(strArray, separator)
Returns concatenation of array of substrings delimited by the separator.
Example JSON Download