Skip to content

Commit

Permalink
Fixes #1; adds support for fields marked as required in the online de…
Browse files Browse the repository at this point in the history
…signer.
  • Loading branch information
jangari committed Jul 6, 2024
1 parent 13f5361 commit 9734037
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 9 deletions.
2 changes: 1 addition & 1 deletion CITATION.cff
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ authors:
given-names: "Aidan"
orcid: "https://orcid.org/0000-0001-9858-5470"
title: "Requested and Required Fields"
doi:
doi: https://doi.org/10.5281/zenodo.11906079
date-released: 2024-06-17
url: "https://github.com/jangari/redcap_requested_and_required_fields"
31 changes: 30 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Requested and Required Fields

[![DOI](https://zenodo.org/badge/816116155.svg)](https://zenodo.org/doi/10.5281/zenodo.11906078)

This REDCap External Module provides functionality for requesting that respondents provide an answer to a field, and displays a warning to survey respondents if any requested fields are missing a value when they try to submit. For completeness, this module also allows required fields to be treated in the same way. Fields can be annotated with @REQUESTED or @REQUIRED, both of which take an optional description, which is shown to the user when they try to submit. If the description is omitted, the field label is shown instead.

![screencast](screencast.gif)
Expand All @@ -12,7 +14,7 @@ This module does not play nicely with embedded fields. Perhaps this could be fix

Unlike traditional required fields, wherein submitting the page commits other values to the database and sets the survey as partially complete, with this module enabled, clicking 'submit' does _not_ save any other entered values. Again, perhaps this could be fixed by running an AJAX call to save the data.

This module only considers fields to be required if they are annotated with @REQUIRED. It might be an idea in future to take fields marked Required in the designer and treat them in the same way.
~~This module only considers fields to be required if they are annotated with @REQUIRED. It might be an idea in future to take fields marked Required in the designer and treat them in the same way.~~

## Installation

Expand All @@ -33,6 +35,7 @@ This module can be configured with the following project settings:

| Setting | Default Value | Description |
| --- | --- | --- |
| Apply to fields marked as required in the project metadata? | false | If checked, fields marked as required in the data dictionary will be treated in the same way as though they were annotated with @REQUIRED. |
| Modal title | "Action Required!" | Title of the popup window showing any requested or required fields. |
| Requested text | "The following fields are requested, although you may submit without completing them:" | Text displayed in the modal window above listed requested fields. |
| Required text | "The following fields are required:" | Text displayed in the modal window above listed requested fields. |
Expand All @@ -47,3 +50,29 @@ This module can be configured with the following project settings:
| Label requested fields | false | Display a label on requested fields. |
| Requested field label text | "* response requested" | Text for requested field label. |
| Requested field label colour | "#0000ff" (blue) | Colour for requested field label. |

## Citation

If you use this external module for a project that generates a research output, please cite this software in addition to [citing REDCap](https://projectredcap.org/resources/citations/) itself. You can do so using the APA referencing style as below:

> Wilson, A. (2024). Requested and Required Fields [Computer software]. https://github.com/jangari/redcap_requested_and_required_fields https://doi.org/10.5281/zenodo.11906079
Or by adding this reference to your BibTeX database:

```bibtex
@software{Wilson_Requested_and_Required_2024,
title = {{Requested and Required Fields}},
author = {Wilson, Aidan},
year = 2024,
month = 6,
url = {https://github.com/jangari/redcap_requested_and_required_fields}
}
```
These instructions are also available in [GitHub](https://github.com/jangari/redcap_requested_and_required_fields/) under 'Cite This Repository'.

## Changelog

| Version | Description |
| --- | --- |
| 1.0.0 | Initial release. |
| 1.1.0 | Added support for fields marked as required in the project metadata. Fixes PHP8.0 compatibility. |
51 changes: 44 additions & 7 deletions RequestedAndRequiredFields.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?php namespace INTERSECT\RequestedAndRequiredFields;

use \REDCap as REDCap;
use \Project as Project;
use ExternalModules\AbstractExternalModule;

class RequestedAndRequiredFields extends \ExternalModules\AbstractExternalModule {
Expand All @@ -15,36 +16,72 @@ function getTags($tags, $fields, $instruments) {

function redcap_survey_page($project_id, $record, $instrument) {

// Collect project settings
$settings = $this->getProjectSettings();

// Get all annotated fields
$requestedTag = "@REQUESTED";
$requiredTag = "@REQUIRED";
$tags = array($requestedTag, $requiredTag);
$annotatedFields = $this->getTags($tags, $fields=NULL, $instruments=$instrument);

// Extract field names and build the new structure, with fieldType and description (or label if unset in the tag)
// Extract field names and build the new structure, with fieldType and description (or label if not set in the tag)
$requestedFields = [];
foreach (array_keys($annotatedFields[$requestedTag]) as $fieldName) {
if (!empty($annotatedFields[$requestedTag]) && is_array($annotatedFields[$requestedTag])) {
foreach (array_keys($annotatedFields[$requestedTag]) as $fieldName) {
$fieldType = REDCap::getFieldType($fieldName);
$description = trim($annotatedFields[$requestedTag][$fieldName][0], '"');
if (strlen($description) == 0) $description = $this->getFieldLabel($fieldName);
if (strlen($description) == 0) $description = $this->getFieldLabel($fieldName);
$requestedFields[$fieldName] = [
'type' => $fieldType,
'description' => $this->escape($description)
];
};
};
$requiredFields = [];
foreach (array_keys($annotatedFields[$requiredTag]) as $fieldName) {
if (!empty($annotatedFields[$requiredTag]) && is_array($annotatedFields[$requiredTag])) {
foreach (array_keys($annotatedFields[$requiredTag]) as $fieldName) {
$fieldType = REDCap::getFieldType($fieldName);
$description = trim($annotatedFields[$requiredTag][$fieldName][0], '"');
if (strlen($description) == 0) $description = $this->getFieldLabel($fieldName);
$requiredFields[$fieldName] = [
'type' => $fieldType,
'description' => $this->escape($description)
'description' => strip_tags($description)
];
};
};

// Collect project settings
$settings = $this->getProjectSettings();
// Add fields marked as required in the metadata to the requiredFields array
if ($settings['designer-required'] == '1'){
$Proj = new Project($project_id);
// Loop through all fields in the current instrument
$instrumentFields = REDCap::getFieldNames($instrument=$instrument);
foreach ($instrumentFields as $this_field) {
// If the field is required AND it is not already in thr requiredFields array
if ($Proj->metadata[$this_field]['field_req'] == '1' && !array_key_exists($this_field, $requiredFields)){
$fieldType = REDCap::getFieldType($this_field); // Get the type
$description = $this->getFieldLabel($this_field); // Get the label
$requiredFields[$this_field] = [
'type' => $fieldType,
'description' => strip_tags($description)
];
};
};
};

// Sort requiredFields by the order of the fields in the instrument, using the instrumentFields array from earlier
$requiredFieldsSorted = [];
foreach ($instrumentFields as $field) {
if (isset($requiredFields[$field])) {
$requiredFieldsSorted[$field] = $requiredFields[$field];
};
};
$requiredFields = $requiredFieldsSorted;

// Let's stop if both requestedFields and requiredFields are empty
if (empty($requestedFields) && empty($requiredFields)){
return;
};

// Language defaults
$settings['modal-title'] = $settings['modal-title'] ?? $this->tt('modal-title-text');
Expand Down
6 changes: 6 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@
}
],
"project-settings": [
{
"key": "designer-required",
"tt_name": "designer-required",
"name": "Apply to fields marked as required in the project metadata?",
"type": "checkbox"
},
{
"key": "modal-title",
"tt_name": "modal-title",
Expand Down
1 change: 1 addition & 0 deletions lang/English.ini
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ name = "Requested and Required Fields"
description = "Provides functionality for requesting a response to a field, and displays a warning to survey respondents if any requested fields are missing a value. For completeness, this module also allows required fields to be treated in the same way. Fields can be annotated with @REQUESTED or @REQUIRED, both of which take an optional description, which is shown to the user. If the description is omitted, the field label is shown instead."

; Configuration settings
designer-required = "Apply to fields marked as required in the project metadata?"
modal-title = "Modal title<br/>Title of window that pops up alerting the user to missing fields.<br/><em>Default: Action Required!</em>"
modal-requested-header = "Modal header text for requested fields<br/><em>Default: The following fields are requested, although you may submit without completing them:</em>"
modal-required-header = "Modal header text for required fields<br/><em>Default: The following fields are required:</em>"
Expand Down

0 comments on commit 9734037

Please sign in to comment.