OpenSpecimen allows configuring calculated fields to be displayed on overview pages.
Example 1: Display participant concatenated first name and last name
Click here to expand...
{
"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 expand...
{
"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 expand...
{
"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 expand...
{
"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 expand...
{
"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 expand...
{
"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 expand...
{
"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 expand...
{
"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 expand...
{
"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 expand...
{
"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 expand...
{
"name" : "calcCpr.isPartial",
"caption" : "Is Consented?",
"type" : "span",
"displayExpr" : "consents != null ? (((consents['GEN-001'] != null && consents['GEN-001'] == 'Yes') || consents['GEN-002'] == 'Yes')?'Yes':'No') : '###'"
}
Example 12: Display BMI of participant
Click here to expand...
{
"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 expand...
...
},
{
"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 expand...
...
,
{
"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 expand...
{
"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 expand...
{
"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 expand...
{
"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 expand...
{
"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 expand...
"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 expand...
{
"name" : "calcSpecimen.numberField",
"displayExpr" : "fns.ifNotNull(specimen.extensionDetail.attrsMap.number1,((+specimen.extensionDetail.attrsMap.number1)/100), 'Not Specified')",
"caption" : "Divided Cal Field",
"type" : "span"
},
Inbuilt Functions
Click here to expand...
Function | Description |
---|
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
Calculated URL
From v10.2 onwards, on the JSON configured overview page, calculated fields can be used to display the hyperlinked URLs.
//Example Code
{
"name" : "calcSpecimen.computedUrl",
"caption" : "Specimen overview page",
"type" : "text",
"displayExpr" : "https://test.openspecimen.org/#/cp-view/{{cpr.cpId}}/participants/{{cpr.id}}/visits/specimens/detail/overview?specimenId={{specimen.id}}&visitId={{specimen.visitId}}",
"linkText" : "View Image"
}
Below is the list of fields that are available to be used in the JSON
Field | Syntax |
Collection Protocol Identifier | cpr.cpId |
Participant Registration Identifier | participant.id |
Participant Identifier | cpr.id |
Visit Identifier | specimen.visitId |
Specimen Identifier | specimen.id |