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 獲取許可證副本。