OpenClinica 用户手册/长列表
对于单选等响应类型,Excel 模板中的 RESPONSE_VALUES_OR_CALCULATIONS 字段包含用户可用的选项描述。此字段允许的最大字符数为 4000。虽然这通常足够,但在某些情况下,处理非常长的列表时,它就不够用了。本页提供了三种方法,说明如何规避此问题。第一种方法适用于 CRF 中的长列表是某个非重复组的一部分的情况。在此方法中,将一个非 OC 单选添加到 CRF 中,并用来填充一个只读的 OC 文本字段。第二种方法描述了如何处理重复组。它涉及找到动态创建的 ID、打开一个包含长列表的新窗口,并根据所选值更改 CRF 中一个只读文本的值。最后一种方法是对第二种方法的改进,它为单选添加了一个工具提示。
本页始终使用解剖学治疗化学 (ATC) 分类作为示例,该列表包含药物代码和描述。
在此方法中,一般思路如下:
- 创建一个描述长列表的外部 XML 文件。
- 创建一个包含 OC 文本字段和非 OC 单选的 CRF。
- 在 CRF 中添加一些脚本,这些脚本可以:
- 将文本字段设置为只读。
- 读取 XML 文件并填充非 OC 单选。
- 将所选值从单选复制到文本字段。
外部 XML 文件应该描述您的列表。为了说明 XML 文件应该是什么样子,以下是一个示例:
<?xml version="1.0" encoding="utf-8" ?>
<ATCList>
<ATCCode Code="A02BC01">
<Description>A02BC01 - Omeprazole</Description>
</ATCCode>
<ATCCode Code="A02BC02">
<Description>A02BC02 - Pantoprazole</Description>
</ATCCode>
...
</ATCList>
示例文件名为“ATC_Codes.xml”。该文件必须存储在您的 OC 服务器上,例如在 includes 目录中,以便从您的 CRF 访问它。
XML 必须包含一个根元素,它只是列表的名称,<ATCList>;它不会在任何地方使用。接下来,必须定义元素。ATCCode 是元素的名称,它将在后面的 JavaScript 中用来查找元素。Code 是实际的代码,它基本上是 Excel 的 RESPONSE_OPTIONS_TEXT 条目之一。Description 是用户为此代码可见的描述,类似于 Excel 的 RESPONSE_VALUES_OR_CALCULATIONS。
CRF 需要两项:
- 一个文本字段,在示例中称为 textOut。
- 一个非 OC 单选,在示例中称为 myList。
textOut 只是一个普通的 OC 文本字段。为了能够在脚本中找到它,它必须用 span 标签包围,并指定一个标识符。因此,LEFT_ITEM_TEXT 变为:<span id=myOutput>textOut</span>
可以通过应用 HTML “select” 标签并通过 “option” 标签添加选项来创建非 OC 单选。
<select id="myList">
<option val="None"/>None
</select>
这将创建一个标识符为“myList”的单选,并且当前它有一个名为“None”的选项。该下拉列表的一个不错的放置位置是 textOut 的右侧,可以通过将 HTML 代码粘贴到 RIGHT_ITEM_TEXT 中来完成。到目前为止,CRF 看起来像这样:
剩下的工作就是添加一些脚本,这些脚本可以将 textOut 字段设置为只读、读取 xml 文件、填充单选并将单选的值复制到 textOut 字段。
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script lang="Javascript">
$.noConflict();
jQuery(document).ready(function($) {
var myField = $("#myList")
var myOutputField = $("#myOutput").parent().parent().find("input");
myOutputField.attr("readonly",true);
$.ajax({
type: "GET",
url: "includes/ATC_Codes.xml",
dataType: "xml",
success: parseXML
});
function parseXML(xml){
$(xml).find("ATCCode").each(function(){
myField.append($("<option />").val($(this).attr("Code")).text($(this).find("Description").text()));
});
myField.val(myOutputField.val());
}
myField.change(function(){
myOutputField.val(myField.val());
myOutputField.change();
});
});
</script>
将此粘贴到 RIGHT_ITEM_TEXT 的一个位置。必须更改四项以适应您的具体情况:
- url: “includes/ATC_Codes.xml” 必须包含指向 xml 文件位置的链接。
- 在 parseXML 函数中,“ATCCode”、“Code”和“Description”必须与您在 xml 文件中定义的标签匹配。
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script lang="Javascript">
$.noConflict();
我们首先要做的是包含 jQuery 1.9.1。您也可以选择包含 OpenClinica 的 jQuery 版本。此外,我们通过调用 noConflict 来防止与 OpenClinica 的代码发生可能的冲突。
var myField = $("#myList")
var myOutputField = $("#myOutput").parent().parent().find("input");
myOutputField.attr("readonly",true);
为了访问非 OC 单选和 OC 文本字段,我们使用前面定义的标识符定义了两个变量 myField 和 myOutputField。然后,我们将 myOutoutField 设置为只读,以防止用户手动输入值。
myField.change(function(){
myOutputField.val(myField.val());
myOutputField.change();
});
当 myField(单选列表)更改时,输出字段的值将设置为单选列表的值。然后,OC 会通过调用字段的 change 函数来通知字段已更改。这确保了在按下保存按钮时将数据保存到数据库中。
$.ajax({
type: "GET",
url: "includes/ATC_Codes.xml",
dataType: "xml",
success: parseXML
});
在此,使用 ajax 来读取 xml 文件。url 指向文件的位置。当文件成功读取后,将调用 parseXML 函数。
function parseXML(xml){
//find every ATCCode and Description
$(xml).find("ATCCode").each(function(){
myField.append($("<option />").val($(this).attr("Code")).text($(this).find("Description").text()));
});
myField.val(myOutputField.val());
}
在我们的 XML 文件中,我们定义了“ATCCode”。parseXML 会尝试在 xml 文件中找到 ATCCode 的每个实例,并为每个实例将一个 option 标签追加到单选 myField。option 具有一个值,该值是 xml 文件中“Code”后面的值,以及一个描述性文本,该文本是 xml 文件中“Description”的值。最后,将单选的当前值设置为文本字段的当前值。这确保了在用户在之前保存数据后输入表单时,两者匹配。
CRF 现在看起来像这样:
将 XML 文件上传到您的 OC 服务器并将您的 CRF 上传到 OC 后,您应该得到以下内容:
重复组需要不同方法的原因主要有两个:
- 非 OC 单选不会出现在重复组中,因为它不是模板的一部分。因此,需要另一种方法来向用户提供长列表。
- 处理标识符在重复组中更加复杂。在方法 1 中,通过将 span 标签应用于 OC 文本字段,我们得到了一个指向目标字段的静态链接。对于重复组,字段是动态生成的,因此 span 标签方法不再适用。
在第二种方法中,一般思路如下:
- 创建一个描述长列表的外部 XML 文件。
- 创建一个包含组中 OC 文本字段的 CRF。
- 在 CRF 中添加一些脚本,这些脚本可以:
- 将文本字段设置为只读。
- 检查是否需要打开新窗口,如果需要,则打开窗口。
- 创建一个包含长列表的外部 HTML 文件,并且:
- 读取 XML 文件并填充非 OC 单选。
- 将所选值复制回 OC 表单。
第一步,创建外部 XML 文件,在方法 1 中进行了描述,并且是相同的。
CRF 需要一项:
- 一个文本字段,在我们的示例中称为 textOut。
然而,如果我们在组中添加一些额外的字段,它会变得更清晰。因此我们还添加
- 一个文本字段,text1
- 一个文本字段,text3
text1 是第一个项目,textOut 是第二个项目,text3 是重复组中的第三个项目。所有项目都在同一个组中,在本例中为 "MyGroup"。
脚本
[edit | edit source]要打开包含单选的窗口,需要在 CRF 中添加一些脚本。一个粘贴此脚本的位置是 LEFT_ITEM_TEXT。
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script lang="Javascript">
$.noConflict();
jQuery(document).ready(function($){
function handlePopup(me){
if(me.attr("ID")!=undefined){
var myID = me.attr("ID");
var gIndex = myID.indexOf(gName.toUpperCase());
if(gIndex!=-1){
var myParent = me.parent();
var colNr = $(myParent).parent().children().index($(myParent)) + 1;
if(colNr==aCol){
atcID = myID;
var handle = window.open("includes/ATC-Form.html");
}
}
}
}
$("table.aka_form_table").on("click", ":input", function(){
handlePopup($(this));
});
var aCol=2;
var gName = "MyGroup";
$("#srh").focus();
});
</script>
您需要针对您的具体情况更改三个项目
- window.open("includes/ATC-Form.html") 必须包含指向 html 文件位置的链接(稍后解释)
- aCol=2 是必须打开新窗口的项目的列号
- gName="MyGroup" 必须包含包含必须打开新窗口的项目的重复组的名称(GROUP_LABEL)
CRF 现在看起来像这样:
工作原理
[edit | edit source]$("table.aka_form_table").on("click", ":input", function(){
handlePopup($(this));
});
由于用户可以动态地向重复组添加新行,我们无法再使用简单的 span 标签来获取目标输入项目的 id。因此,我们为每个输入项目触发 click 事件。为了确保该事件也针对新添加的行触发,应用了 "on" 函数。接下来,我们调用一个函数来处理我们的弹出窗口。
function handlePopup(me){
if(me.attr("ID")!=undefined){
var myID = me.attr("ID");
var gIndex = myID.indexOf(gName.toUpperCase());
if(gIndex!=-1){
var myParent = me.parent();
var colNr = $(myParent).parent().children().index($(myParent)) + 1;
对于刚刚触发事件的项目,我们首先检查它是否具有 ID。如果有,我们将 ID 存储在变量 myID 中。由于一个 CRF 中可能存在多个重复组,我们需要确保我们只为正确重复组中的正确项目打开一个新窗口。幸运的是,OC 根据 GROUP_LABEL 对重复组中的 ID 进行分类。因此,如果我们当前项目的标识符 (myID) 包含正确重复组的 GROUP_LABEL (gName),我们就知道该项目位于正确的组中。这是通过应用 indexOf 函数来完成的。如果返回值为 -1,则 myID 不包含 gName 字符串,并且 if 语句失败。此外,确定项目的列号。由于索引函数是基于 0 的,因此添加 1。
if(colNr==aCol){
me.attr("readonly",true);
atcID = myID;
var handle = window.open("includes/ATC-Form.html");
}
如果列号也恰好是正确的,则该项目应该打开一个新窗口。但是,首先将字段设置为只读,以防止手动编辑,并将 myID 存储在全局 atcID 中。
var aCol=2;
var gName = "MyGroup";
$("#srh").focus();
如前所述,aCol 和 gName 用于确保新窗口仅针对正确重复组和正确列中的项目打开。最后一条语句将页面的初始焦点设置为顶部的保存按钮。这可以防止用户在加载后手动编辑我们的 textOut 字段,而不是通过用户单击该字段来获得焦点。
外部 HTML 文件
[edit | edit source]外部文件是一个简单的页面,包含动态填充的列表和一个选择按钮。
<html>
<head>
<title>Select ATC-code</title>
<meta http-equiv="Expires" content="0"> <!-- disable caching -->
<meta http-equiv="Content-type" content="text/html; charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=8" />
<script src="jmesa/jquery-1.3.2.min.js"></script>
<script type="text/javascript">
jQuery(document).ready(function($) {
$.ajax({
type: "GET",
url: "ATC_Codes.xml",
dataType: "xml",
success: parseXML
});
function parseXML(xml){
$(xml).find("ATCCode").each(function(){
field.append($("<option />").val($(this).attr("Code")).text($(this).find("Description").text()));
});
}
$("#submit").click(function(){
var atcElement = window.opener.document.getElementById(window.opener.atcID)
if(atcElement.value!=$("#atc-list").val()){
atcElement.value=$("#atc-list").val();
atcElement.onchange();
}
close();
});
var field = $("#atc-list");
});
</script>
</head>
<body>
<h1>Select an ATC-code</h1>
<button type="button" id="submit">Select</button>
<select id="atc-list"/></br>
</body>
</html>
此表单必须存储在 OC 服务器上。在本例中,它存储在 includes 目录中,名为 "ATC-form.html"。需要更改几个项目以适合您的特定列表
- 有关 ATC 代码的描述(例如,标题、标题等)
- src="jmesa/jquery-1.3.2.min.js" 依赖于 html 表单的位置。如果它放置在服务器上的 includes 目录中,则无需更改它。
- url: "ATC_Codes.xml" 必须包含指向您的 xml 文件位置的链接
- 在 parseXML 函数中,“ATCCode”、“Code”和“Description”必须与您在 xml 文件中定义的标签匹配。
- id="atc-list" 应该反映您的列表。如果您更改此项,请确保也更改所有 "#atc-list" 字符串
工作原理
[edit | edit source]ajax 和 parseXML 方法在方法 1 中进行了解释。
<body>
<h1>Select an ATC-code</h1>
<button type="button" id="submit">Select</button>
<select id="atc-list"/></br>
</body>
HTML 文档的主体包含一些文本、一个 ID 为 "submit" 的按钮和文本 "Select"。此外,它还包含一个 ID 为 "atc-list" 的空单选。
$("#submit").click(function(){
var atcElement = window.opener.document.getElementById(window.opener.atcID)
if(atcElement.value!=$("#atc-list").val()){
atcElement.value=$("#atc-list").val();
atcElement.onchange();
}
close();
});
当用户按下表单上的按钮时,将检索在 CRF 脚本中声明的全局变量 atcID,并使用此 ID 来查找实际字段 (atcElement)。如果字段的当前值不同于用户选择的 value,则更新该 value。调用 onchange() 以通知 OC,如果按下保存按钮,则必须保存该 value。最后,关闭窗口。
结果
[edit | edit source]将 HTML 表单和 XML 文件上传到您的 OC 服务器并将您的 CRF 上传到 OC 后,您应该获得以下内容
方法 3:使用工具提示的非重复组中的长列表
[edit | edit source]在第二种方法中,我们打开一个新窗口来显示下拉列表。虽然新窗口为程序员提供了很大的自由度,但它的缺点是浏览器有时会阻止新窗口。另一种方法是应用 OC 中包含的工具提示。在第三种方法中,一般方法如下所示
- 创建一个描述长列表的外部 XML 文件。
- 创建一个包含组中 OC 文本字段的 CRF。
- 在 CRF 中添加一些脚本,这些脚本可以:
- 读取 XML 文件并将内容存储在变量中
- 将文本字段设置为只读。
- 检查是否需要显示工具提示,如果是,则显示包含单选的工具提示
- 填充单选
- 将选定的值从单选复制回表单
第一步,创建外部 XML 文件,在方法 1 中有描述,并且是相同的;第二步,创建 CRF,在第二种方法中描述,并且是相同的。
脚本
[edit | edit source]要创建包含单选的工具提示,需要在 CRF 中添加一些脚本。一个粘贴此脚本的位置是 LEFT_ITEM_TEXT。
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script lang="Javascript">
$.noConflict();
jQuery(document).ready(function($) {
var stringData;
$.ajax({
type: "GET",
url: "includes/ATC_Codes.xml",
dataType: "xml",
success: parseXml
});
function parseXml(xml){
stringData = "<option val='None'/>None";
$(xml).find("ATCCode").each(function(){
stringData=stringData+"<option val='"+$(this).attr("Code")+"'/>"+$(this).find("Description").text();
});
}
startTip = function(atcID){
var s="<select id='myList' onchange = 'changeValue()' atcID="+atcID+">"+stringData+"</select>";
Tip(s, CLICKSTICKY, true, CLOSEBTN, true, FOLLOWMOUSE, false, WIDTH, 700);
}
changeValue = function(){
var myOutputID = $("#myList").attr("atcID");
var myOutput = document.getElementById(myOutputID);
var selectedVal = $('option:selected', "#myList").attr("val");
if(myOutput.value !== selectedVal){
myOutput.value = selectedVal;
myOutput.onchange();
}
UnTip();
}
$("table.aka_form_table").on("click", ":input", function(){
var atcID = $(this).attr("id");
var myParent = $(this).parent();
var colNr = $(myParent).parent().children().index($(myParent)) + 1;
var groupIndex = atcID.indexOf(groupName.toUpperCase());
if(groupIndex!=-1){
if(aCol==colNr){
$(this).attr("readonly",true);
atcDescrID = $(this).parent().parent().children(":nth-child(3)").find(":input").attr("id")
startTip(atcID);
}
}
});
var aCol=2;
var groupName = "MyGroup";
$("#srh").focus();
});
</script>
您需要针对您的具体情况更改四个项目
- url: “includes/ATC_Codes.xml” 必须包含指向 xml 文件位置的链接。
- aCol=2 是必须打开新窗口的项目的列号
- groupName="MyGroup" 必须包含包含必须显示弹出窗口的项目的重复组的名称(GROUP_LABEL)
- WIDTH,700;此处 700 应该是您希望工具提示具有的宽度
工作原理
[edit | edit source]$.ajax({
type: "GET",
url: "includes/ATC_Codes.xml",
dataType: "xml",
success: parseXml
});
我们再次使用 ajax 来解析我们的 XML 文件。
function parseXml(xml){
stringData = "<option val='None'/>None";
$(xml).find("ATCCode").each(function(){
stringData=stringData+"<option val='"+$(this).attr("Code")+"'/>"+$(this).find("Description").text();
});
}
但是这次,我们创建了一个名为 stringData 的字符串,其中包含所有选项和描述。
$("table.aka_form_table").on("click", ":input", function(){
var atcID = $(this).attr("id");
var myParent = $(this).parent();
var colNr = $(myParent).parent().children().index($(myParent)) + 1;
var groupIndex = atcID.indexOf(groupName.toUpperCase());
if(groupIndex!=-1){
if(aCol==colNr){
$(this).attr("readonly",true);
atcDescrID = $(this).parent().parent().children(":nth-child(3)").find(":input").attr("id")
startTip(atcID);
}
}
});
其中大部分已经在方法 2 中解释过。但是,包含标识符的 atcID 现在存储在本地。此外,我们使用此标识符调用 startTip。
startTip = function(atcID){
var s="<select id='myList' onchange = 'changeValue()' atcID="+atcID+">"+stringData+"</select>";
Tip(s, CLICKSTICKY, true, CLOSEBTN, true, FOLLOWMOUSE, false, WIDTH, 700);
}
startTip 函数是实际启动工具提示的函数。首先,我们创建一个字符串 "s",它定义了工具提示中使用的下拉菜单。此 select 具有标识符 "myList",稍后用于检索选定的 value。接下来,atcID 与列表一起存储,这对于能够稍后查找单击的字段的标识符是必要的。然后,我们添加 stringData,它是我们在 parseXml 函数中生成的包含所有选项的完整字符串。其余的是工具提示选项 (http://www.walterzorn.de/en/tooltip/tooltip_e.htm)。第一个固定工具提示,第二个添加关闭按钮,第三个阻止工具提示跟随鼠标,最后一个设置宽度。
changeValue = function(){
var myOutputID = $("#myList").attr("atcID");
var myOutput = document.getElementById(myOutputID);
var selectedVal = $('option:selected', "#myList").attr("val");
最后一个函数是 changeValue 函数,它在单选的 onchange 事件触发时被调用。要查找应写入输出的字段,请从列表中检索 atcID 属性。接下来,通过使用标识符调用 getElementByID 来检索实际元素。我们通过使用所选选项的 "val" 属性来检索选定的 value。
if(myOutput.value !== selectedVal){
myOutput.value = selectedVal;
myOutput.onchange();
}
UnTip();
要检查该字段是否实际上需要更改,请将该字段的当前值与选定的值进行比较。如果它们不同,则将该字段更新为新的值,并调用 onchange 函数。最后,关闭工具提示。
结果
[edit | edit source]将 XML 文件上传到您的 OC 服务器并将您的 CRF 上传到 OC 后,您应该获得以下内容
本页面上的编程代码版权所有 2012 - 2014 VU University Medical Center / Center for Translational Molecular Medicine,可以根据 Apache 2.0 许可证重新使用。 除非适用法律要求或以书面形式同意,否则根据许可证分发的软件按“现状”提供,不附带任何明示或暗示的担保或条件。 有关管理许可证的权限和限制的具体语言,请参阅许可证。
您可以在 http://www.apache.org/licenses/LICENSE-2.0 获取许可证副本。