Switching Active Tabs Programattically: Jquery/Bootstrap

There are lots of different ways to control visibility of different types of web elements.

I’m working on the web front end of what will eventually become an HL7 message inspection tool.

I’ve set it up so that when the user pastes an HL7 message into the textarea on the #omsg pane,  the results will be pasted into the #parsedmsg pane.  I then want the latter pane to become visible.

I set all this up using bootstrap tabs.

The tab controls are anchors wrapped in list elements.  To show what tab is visible, Bootstrap relies on the class “active” to be added to the parent li tag.

I don’t know if I’m having an off day but I couldn’t figure out how to have that happen when I switched visibility programmatically.

The panes would switch visibility just fine, but I naturally wanted the active tab button to be highlighted.

Instead of toggling visibility of various elements,  I decided to write a function using DOM traversal to simulate clicking the desired button.

I’ll go into more detail below, but this is the function itself.

function activeTab(newtabid) {
$('#lpane > ul > li > a[href="'+newtabid+'"]').trigger('click');
});

The tab controls are contained in a div with the id of “lpane”.  As Bootstrap tabs rely on the href attribute, its easy enough to find which element to click using that particular parameter.

Here is the HTML

<div id="wrapper" class="col-lg-12">
<div id="header" class="col-lg-12">
<h3>HL7 Tool</h3>
</div>
<div id="lpane" class="col-lg-12 centered">
<ul class="nav nav-pills " style="text-align:center;">
	<li role="presentation"><a data-toggle="tab" href="#omsg">Original Message</a></li>
	<li role="presentation" id="lpmsg"><a class="btn" data-toggle="tab" href="#pmsg" href="#">Parsed Message</a></li>
	<li role="presentation"><a class="btn" data-toggle="tab" href="#redset" href="#">Redaction Settings</a></li>
	<li role="presentation"><a class="btn" data-toggle="tab" href="#redmsg" href="#">Redacted Message</a></li>
</ul>
</div>
<div id="cpane" class="tab-content col-lg-12">
<div id="omsg" class="tab-pane active">
<label for="#omsg">Original Message</label><textarea id="msg" class="form-control" placeholder="Paste Msg Here"></textarea>
<input type="button" class="btn" value="Parse" id="parsemsg"/><input type="button" class="btn" value="Clear" id="clearomsg" />
</div>
<div id="pmsg" class="tab-pane">
<div class="col-md-6" id="parsedmsg"></div>
</div>
<div id="redset" class="tab-pane">
REDSET
</div>
<div id="redmsg" class="tab-pane">
REDMSG
</div>
</div>
</div>

and finally…the actual script


<script>

$(document).ready(function(e){
 
$('#parsemsg').click(function(e){
 
$('#parsedmsg').parsehl7({msgin:$('#msg').val()});
 
 activeTab('#pmsg');
 
 }); //parsemsg
 
 }); //document ready

</script>

 

 

CSS Calc Function

 

Have you ever had a problem getting a div to center?   There are times that for some reason the margin: auto;  just doesn’t work.

Its situations like this that get old timers like me poking around Google where we discover new and cool things.   (the whole having a job, and being expected to produce results thing can make that difficult at times).

This led to the discovery of the calc()  function!

Calc allows you to use math to size elements without having to resort to scripting.

In the example below,  I set up a lightbox div with a width that is 100 pixels less than half the width of the parent div  (calc(50% – 100px);).

In order to center this (because margin:auto wasn’t working for some reason),  I used (calc((100% – (50% – 100px))/2);)

 

.lightbox {
margin-top:20px;
 width:calc(50% - 100px);
 left: calc((100% - (50% - 100px))/2);
 height:auto;
 padding:15px;
 margin-left:auto;
 margin-right: auto;
 position:absolute;
 border: #110ef3 solid 2px;
 border-radius: 5px;
 background-color: #FFF;

}

Database Result Set to HTML Table Function in PHP

Hi All;

I’m looking at a situation where I need to have several database tables view-able on a web front end without a lot of time to do it.

I created a quick and dirty function to accomplish this.  I thought others might find it useful.


function resultset2html($tblclass,$tblid,$headers,$resultset,$title = null,$titleclass = null) {

//$tblclass:  The html class for the table
//$tblid:  The html id for the table
//$headers:  An array of column headers
//$resultset:  The resultset from the PDO query
//$title: Optional table title
//$titleclass: Optional table title class
$output = "<table class='$tblclass' id='$tblid'>";   //sets up the output.

//creates a table title if specified
if ($title != null) {
if ($titleclass == null) {
$titleclass = '';
} else {
$titleclass = "class='$titleclass'";
}
$output .= "<tr $titleclass>";
$colcount = count($headers);
$output .= "<th colspan='$colcount'>".$title."</th>";
$output .= '</tr>';
}

//header row
$output .= "<tr>";
foreach($headers as $colh) {

$output .= "<th>".$colh."</th>";  //creates header row

}

$output .= '</tr>';

foreach($resultset as $row) {   //iterates through result set

$output .= '<tr>';

foreach ($row as $line) {  //iterates through each column of result set

$output .= "<td >".$line.'</td>';


}

$output .= '</tr>';


}

$output .= '</table>';

return $output;

}

Here is the code where I retrieve the result set from a PDO connection ($dbh) and send it to the function.

I’m using Bootstrap for most of my formatting.


$sql = "SELECT rsndmsg,odatetime,lresenddt,attempts,discard,discardreason,notes FROM hrm_resends WHERE sent = 0";

$q = $dbh->prepare($sql);
$q->execute();

$resends = $q->fetchAll(PDO::FETCH_ASSOC);

$headers = array('Message Id','Original Date/Time','Last Attempt','# attempts','discard','Discard reason','Notes');

$resendtable = resultset2html('table-striped table-bordered', 'resends',$headers, $resends,"Messages Queued for Resend","tbltitle");

This is the non Bootstrap css I levered in:


td,th {
padding-left:5px;
padding-right:5px;
}

.tbltitle th {
background-color:#0073EA !important;
color:#FFF;
text-align: center;
font-weight: bold;
font-size:large;
}

and, here is the output!

php_resultset2html

MEDITECH and iPeople Echo: Providing near real time patient census data

Anyone whose worked with the Meditech Magic Hospital Information System knows that sometimes it can be a challenge to pull useful and timely statistical data from it.

Late last year, the Huron-Perth Healthcare Alliance implemented the iPeople Connect product which includes Echo an application that allows us to build our own SQL Server based data-repository,  specifying what data we want from our Meditech system,  and how frequently to update it.

What this does is allows us to provide our client base with a broad range of reports and reporting tools instead of the text based reports generated by Meditech’s NPR report writer.

One of the very first requests we received was to provide near real-time patient census data.

The project, dubbed Atlas,  asked for the following data elements:

  • Location
  • Bed Count
  • Patient Count
  • Empty Beds
  • Occupancy Rate
  • Isolation Patients
  • Pending DC dates prior to current date
  • Pending DC dates on current day
  • ALC patient counts

Anyone who has ever faced pulling data from Meditech knows that it be difficult figuring out where the data is stored.

With the help of iPeople Scout,  an application that allows us to search the Meditech Dictionaries,  and view joins,  we found that the best Meditech source table was ADM.ADMStatsInLocation.   This table gave us the bed census data for each location, as of the midnight run on any given date.

While all this seems straight forward,  there was a complication in how to define a bed.

I know what you’re thinking,  “a bed is something that you sleep in, or on…and its where hospitals keep patients!”.    You’d be correct,  except that our organization may have several entries for the same physical bed in the Meditech dictionary.    The reason for this is that some beds may be either acute,  or chronic.  It all depends on what type of patient gets admitted.

My preference is that data elements be identified programmatically.    After spending several hours running test queries,  trying to ensure that our virtual bed count matched our physical bed count I realized that this was impossible.   The reason is that those pesky humans might get in there and create a bed that wouldn’t fit the existing naming convention.

I opted instead to use an associative array within the PHP script that contained the official bed counts for each facility and location.

The next, and most difficult challenge to solve, was how to identify ALC patients.

For those unfamiliar with the term,  ALC means (Alternative Level of Care).   This term refers to patients occupying acute beds,  who are ready for discharge,  but do not have a place to go.   They still require care (long term facility,  chronic or palliative etc),  but there are no beds for them to go to.

When I first reviewed the specifications,  I figured this would be a flag,  perhaps a custom query somewhere within ADM.   I was somewhat mortified to learn that the only way to identify an ALC patient was through ALC orders.

This was complicated by the fact that a patient who has been in hospital for some time,  could be designated ALC several times through their stay.

Within the organization we have several ALC order types in our OE.ORD dictionary.

  • Identify:  indicates that the patient is an ALC patient
  • Change:  changes the order
  • Discontinue:  discontinues the order,  however the patient remains in that bed, and
  • Discharge:  the patient is discharged

It took several days to work this out,  and it was only with the assistance of our Nursing Informatics team,  as well as input from Bed Management that I managed to figure it out at all.

In order to identify,  and add a patient to the ALC tally,   while compiling the information,   I query OE.ORD for each in patient,   looking for any ALC orders for their current visit.

I pull the data sorted in descending order by order date and time.

This is the logic I use:

If the query gets no results,  then patient is not now,  nor has ever been an ALC patient.   I then set the ALC flag within the XML node for this patient to “no”.

If there are results,  I check to see if the last result is a discontinue or discharge.   If it is,  this indicates that the patient was an ALC patient.   I set the ALC attribute to “expired” for these patients.

The only option left at this point is that the patient is an alc patient.   I increment the appropriate counters,  and set the ALC flag to “yes”,  which is used for display and functionality as the user can pull up a patient’s entire ALC order history in this case.

Other data types,  such as Isolation and Pending Discharge are determined by checking custom query fields which are exported into the SQL Server database.

All this information is formatted into an XML document by a PHP script.   In order to save time on processing,  the script is run every 10 minutes by a cron job,  and the results written to a file on the web server.

When a user accesses the Atlas home page,   it is this file that is accessed,  saving the user a long wait each time they go looking for data.

There is functionality that checks the age of the data,  and,  if it is older than 10 minutes,  the user be flagged, and notified to call IT to report a problem.

The front end is a simple web page,  with JQuery/javascript programming that will take the XML document and dynamically create tables using Document Object Model traversal methods.

The user has the ability, via checkboxes, to limit which sites within the organization they want to see.

Upon page load,  each site is collapsed.   The user can view or hide site specific locations by clicking on the desired site.

The screenshot below shows the Stratford General Hospital locations expanded.

censusbigscreenshot

Other functionality includes the ability to view a list of patients in each location.   The list only uses account numbers,  reducing the risk of a privacy breach.

Within the individual patient list,  the user can view a history of ALC orders for patients that have them.

They can also view a list of patients for whom there is a pending discharge.

Managers and other stakeholders receive a static copy of this report via email every morning at 7am.

The iPeople DR,   combined with the ability to use modern programming languages has allowed us to improve patient flow, and service delivery to our patients.

PHP: Find index of specific value in nested array

Array recursion is a bit of a bear to tackle for any programmer.

While working on an HL7 parser,  I needed to be able to determine where in the HL7 message a certain string was located.   As I parsed the HL7 message into an array,  I needed to do a recursive search.

There are many solutions out there,  but when I first tried to tackle this,  the ones that I found that worked,  would either only tell me if a value existed in a nested array, but not what the index was,  or would only give me the root index.

After much trial and error,  I finally came up with a solution that is elegant and will return the location index, regardless if its associative or numeric.

The key to recursion is writing a function that can call itself.

The logic I use is to iterate through an array using foreach,   check  if the current value is an array,   if so,  call the recursion function and concatenate the value returned (if any).

This gives me a bar delimited string,  showing me exactly where in the nested array my search string exists.

Here is my function:


<?php

function recurse($input,$string) {

if (!is_array($input)) {

return 'Input parameter must be an array!';

}

$out = ''; //As I'm returning a delimited string, I need to declare the output string

foreach($input as $key=>$val) {

if (is_array($val)) {

$r = recurse($val,$string);

if (strlen($r) > 0) { //checking the length prevents you from getting a return for every index

$out .= $key.'|'.$r; //I chose bar delimited, you can change this to whatever, or even use an array

}

} else {

if ($val == $string) {

$out .= $key;

}
}

}

return $out;
}

?>

While I wrote this for HL7 parsing, I’ve created a script with some generic arrays to demonstrate


$sarr = array(

 'BILLY' => 'BLASTOFF',
 'RUBBER' => 'DUCKY'

);

$narr = array(

 'FIVE' => 5,
 'SIX' => 6,
 'SEVEN' => 7,
 'TOYS' => $sarr

);

$test = array (

 'ONE' => 1,
 'TWO' => 2,
 'THREE' => 3,
 'FOUR' => $narr,

);

echo '<pre>';
print_r(recurse($test,2));
echo '<br>';
print_r(recurse($test,7));
echo '<br>';
print_r(recurse($test,'DUCKY'));

and here’s the output!

 

TWO
FOUR|SEVEN
FOUR|TOYS|RUBBER

 

 

PHP: Tracking session variable content while developing

I like using session variables to track various and sundry as users navigate through my sites.

The problem comes when I forget to change, or load a session variable.

What I used to do was add var_dump($_SESSION) lines to my scripts…but of course, then you have to go remove them.

This weekend I thought of a cleaner way.

I create a whole new file, usually sessvar.php. I then point my browser to it, and whenever I need to see what the session variables are, I simply refresh the page.

So, you’d navigate to yourpageurl/sessvar.php in a tab besides what ever you’re using to check your work, and refresh the sessvar.php page whenever you needed to see what variables your stored were.

<?php

session_start();

var_dump($_SESSION);

?>

JQuery/HTML: Handling events for elements created after initial page load.

My regular readers already know that I add a lot of stuff to my pages programmatically using PHP. Naturally much of this code is added after the initial page load.

I used to defeat this by loading in the scripting with the new elements, but that’s very tedious, and honestly, sloppy.

The issue is that new elements aren’t registered with the Document Object Model (DOM) set up when the page loads.

To get around that you can sort of “pre-register” these elements using JQuery’s .on method.

Here’s the syntax:


$(document).on([event],[selector],function(e) {

//do your stuff here

});

Here’s a working example from an actual piece of code I’m working on.

In this example I’m posting data to a php script when the target element (id=”edname_1″) loses focus, provided it doesn’t match what’s there already. I do this by loading the contents of the control into txtval on the focusin event.

var txtval = '';    //global variable.
		
		
		    $(document).on("focusin","#edname_1",function(e){
		    	
		    	txtval = $(this).val();   //loads global
		    	
		    });
		
			$(document).on("focusout","#edname_1",function(e){
				
					if ($(this).val() == txtval) {
						console.log("doing nothing");
						return;
						
					}
				
					if($(this).val().length < 1) {
						
						alert("This shouldn't be blank");
						return;
						
					}
				console.log("updating");
				$.post('PHP/updateftable.php', {field: $("#activefld").val(), val: $(this).val()}) 
                                            
                                        /*
                                         In order to avoid having to add the db table primary key of the row I want to update to every element I add to the div,                         
                                         I created a hidden field and placed that key as the value.
                                         */

				.done(function(data){
					
					console.log(data);   //checks the output.
							
				});
				
	
			});
		


This example is from a piece of actual code for a project in development, so there’s some exception handling, etc. I haven’t done yet.