Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 5 Next »

Problems

Yes/no Answers

There are key problems in many if not most htmlforms involving the distinction between radio buttons and checkboxes. Radio buttons can be used in openMRS when there is a concept with several coded answers to choose from. However, sometimes the concept is 'symptom present' or 'symptom absent' with coded answers for a series of symptoms. The question being asked on the form may be 'does the patient present with a cough?' with the answers 'yes' or 'no.' But, from the system's prospective, it is really two questions: 'Is a cough present?' and 'Is a cough absent?'

Irrelevant Form Sections

Sometimes, on a paper form clinicians record many details about one specific question. A clinician might want to know 'Does the patient present with a cough?' and then 'How long has the cough persisted?' and 'How serious is the cough?' When the form is rendered as an htmlform, there is a possibility that a user will enter impossible data by accident. It is possible for a series of responses to indicate that the patient had 'no cough that persisted for 3 weeks and was extremely serious.'

Both of these problems could theoretically be solved with standard Javascript. One can give inputs IDs and then generate complex rules. Unfortunately, we don't actually write the input tag in openMRS, we use the obs tag. The obs tag translates into one hidden input and one actual input when it is rendered as HTML. Simple Javascript has no method of handling this problem.

Solutions

The Javascript

Using the JQuery library while making slight modifications to the markup we can achieve simple solutions to both these problems. The following script can be copied toward the top of your htmlform.

<script type="text/javascript">
if(jQuery){
 $j(document).ready(function(){
 if ( $j.browser.msie ) {
 $j(":checkbox").click(function(){
 $j(this).change();
 });
 }
 $j(".enableDisable").each(function(){
 var group = $j(this);
 function disableFn(){
 group.children("#disabled").fadeTo(250,0.33);
 group.children("#disabled").find(":checkbox").attr("checked",false); //uncheck
 group.children("#disabled").find("input[type$='text']").val("");
 group.children("#disabled").find("input").attr("disabled",true);  //disable
 }
 function enableFn(){
 group.children("#disabled").fadeTo(250,1);
 group.children("#disabled").find("input").attr("disabled",false);
 }
 disableFn();
 $j(this).children("#trigger").find(":checkbox:first").change(function(){
 var checked = $j(this).attr("checked");
 if(checked == true){
  enableFn();
 }else{
  disableFn();
 }
 });
 });


 $j(".checkboxGroup").each(function(){
 var group = $j(this);
 var uncheckAll = function(){
 group.find("input[type$='checkbox']").attr("checked",false);
 group.find("input[type$='checkbox']").change();
 }
 var uncheckRadioAndAll = function(){
 group.find("#checkboxAll,#checkboxRadio").find("input[type$='checkbox']").attr("checked",false);
 group.find("#checkboxAll,#checkboxRadio").find("input[type$='checkbox']").change();
 }



 group.find("#checkboxAll").find("input").click(
 /*  This was tricky... A number of things needed to happen
 Basically, This is supposed to treat a group of inputs as if
 were all one big checkbox. It is designed so that a checkbox
 can be next to an input, and the user clicks the input, the
 checkbox checks as well. But, when the user clicks the checkbox,
 the browser marks the checkbox as checked. Therefore, when we check
 if the checkbox is already checked, it always respondes true...
 We needed to have 2 cases: when the clicking action is on the first checkbox
 and when the action is on any other.  */
 function(){
 var flip;
 var checked = $j(this).siblings(":checkbox:first").attr("checked");
 if($j(this).attr("name") == $j(this).parents("#checkboxAll:first").find(":checkbox:first").attr("name")){
 checked = $j(this).attr("checked");
 flip = checked;
 }else{
 flip = !checked;
 }
 if($j(this).attr("type") == "text") if(flip == false) flip = !filp; // this is so the user doesn't go to check the checkbox, then uncheck it when they hit the input.
 uncheckAll();
 $j(this).parents("#checkboxAll:first").find(":checkbox").attr("checked",flip);
 $j(this).parents("#checkboxAll:first").find(":checkbox").change();
 }
 );



 group.find("#checkboxRadio").find("input[type$='checkbox']").click(function(){
 uncheckAll();
 $j(this).siblings("input[type$='checkbox']").attr("checked",false);
 $j(this).attr("checked",true);
 $j(this).change();
 });

 group.find("#checkboxCheckbox").click(
 function(){
 uncheckRadioAndAll();
 }
 );
 });
 });
}
</script>

First, JQuery is included. Next, the script checks to see if JQuery is loaded properly. If so, it proceeds. This means that if there is problem with JQuery, the script will do nothing, and the form will render as it would with no scripting.

The Markup

In order for the Javascript to work correctly, it needs to know where to look for input tags. If you want to employ a rule, you must wrap your obs tags in another tag with a series of classes and IDs.

checkboxGroup

This function is arguably hard to understand. It makes much more sense once you see an example. When the javascript encounters an element with a class of 'checkboxGroup' it looks inside for child elements with the following IDs: 'checkboxCheckbox, checkboxAll, checkboxRadio.' Each child element can contain one or more checkboxes in them. When a checkbox in one of the child elements is checked, the checkboxes in each of the other child elements are unchecked. Additionally, based on which ID the child element has, a different behavior is achieved inside the child element. For checkboxCheckbox, more than one checkbox inside the child element is allowed to be checked. In checkboxAll, every checkbox in the child element is checked or unchecked. In checkboxRadio, the checkboxes have the function of radio buttons, and only one is allowed to be checked at a time.

Now for an example:

In the physical examination of a form, there is a line for lungs. The possible answers are 'normal,' 'absent,' 'noisy,' and 'crackly.' The rule we need to express: 'normal can be selected OR ANY of the others but not both. Any of the abnormal sounds can be checked, even more than one, but they cannot be checked at the same time as normal. Here is the code:

<tr>
				<td align="right">lungs:</td>
				<td class="checkboxGroup">
					<span id="checkboxAll"><obs conceptId="3238" answerConceptId="3236"
						answerLabel="normal" style="checkbox" /></span>
					<span id="checkboxCheckbox"><obs conceptId="3238" answerConceptId="5622"
						answerLabel="dull/absent" style="checkbox" />
					<obs conceptId="3238" answerConceptId="5209"
						answerLabel="noisy" style="checkbox" />
					<obs conceptId="3238" answerConceptId="3239"
						answerLabel="crackles" style="checkbox" /></span>
				</td>
			</tr>

The following images demonstrate the possible selections:

None

Normal

NOT normal, two selections.

enableDisable

When the script comes across an element with the class 'enableDisable,' it looks for the two child elements with the following IDs: 'trigger', 'disabled.' The first (and preferably only) checkbox in the trigger element will toggle the status of the inputs and style of everything in the 'disabled' element. This means, for the question 'Does the patent have a cough,' 'yes' can be a trigger for more detailed questions to apear. The two solutions can be combined in the following code example and corresponding images.

<tr>
				<td align="right">Toux:</td>
				<td class="checkboxGroup">
					<obsgroup groupingConceptId="1292">
						<span id="checkboxAll"><obs conceptId="1734" answerConceptId="107"
							answerLabel="non" /></span>
						<span id="checkboxCheckbox" class="enableDisable">
							<span id="trigger"><obs conceptId="1293" answerConceptId="107" answerLabel="oui" /></span>
							<span id="disabled">
								durée:
								<obs conceptId="2160" />
								semaine
								<obs conceptId="2240" />
								mois
								<obs conceptId="1293" answerConceptId="2128"
									answerLabel="seche" />
								<obs conceptId="1293" answerConceptId="970"
									answerLabel="hemoptysie" />
								<obs conceptId="1293" answerConceptId="5957"
									answerLabel="productive" />
								,
								<obs conceptId="2130" labelText="aspect" />
								<obs conceptId="1293" answerConceptId="5960"
									answerLabel="dyspnee" />
							</span>
						</span>
					</obsgroup>
				</td>
			</tr>

Note: The use of the span tag is not advised for this feature because it is not supported evenly across all browsers. Specifically, certain versions of internet explorer will not fade transparencies on span elements. The div tag with additional CSS is the preferred method. Td and tr tags are also fine candidates.

  • No labels