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>

 

 

JQUERY: Handle a click event on an HTML element within another clickable element

Confusing title?

Let me explain:

I’m working on a project that will allow my employer’s senior team a patient census board. (I work for a hospital if the “patient” thing didn’t give it away).

As this project spans 4 different hospitals,  I present the initial data in collapsed tables,  populated by JQuery from an XML document passed from a PHP script.

In order to expand a table,  I allow the user to click the appropriate row.

Yesterday I was asked to add some new functionality that would allow the user to call up a list of patients by clicking on a column within that row.

The information in this column is wrapped in a span for display purposes,  so I hooked onto that.

Of course,  when I click on it,  both the span click event, AND the row click event fire!

I prevent this,  by placing the span click event handler above the row click event handler in the js file AND ending the span click even with return false;

This is how the table structure is set up


<table>
<tr>
<th>header row</th>
</tr>
<tr class="exoccclick">
<td>Something</td>
<td>Another Thing</td>
<td><span class="pdcold">53</span></td>
</tr>
</table>

And this is the click handling code for both the tr class (exocclick) and the span class (pdcold)


$(document).on('click','.pdcold',function(e){

var tbid = $(this).closest('table').attr('id');

console.log('pdcclick ' + tbid);

return false;  //<--don't forget this bit!
});

$(document).on('click','.exoccclick',function(e){

//some stuff

});

As this is internal I can’t link the actual page,  but here’s a screen shot of what the row looks like:

The Pend DC Old column is the span class where I added the click handler

The Pend DC Old column is the span class where I added the click handler (click to enlarge)

JQuery Quick Tip: Loop through each visible object

Hi;

I need to loop through some checkboxes identified by a class.

There are lots of “try this” in the forums, so I wanted to post what worked in jquery 1.11.1

This iterates through objects of a class selector that are visible and concatenates their ID to a string.

….because I wanted the example to be simple,  that’s why.

 


$('.aacheck').filter(':visible').each(function(i,o) {    //i: iteration  o: object

chdept += '~' + $(o).attr('id');

}

If you need to check multiple conditions (like checkboxes that are visible AND checked)…


$('.aacheck').filter(':visible').filter(':checked').each(function(i,o) {    //i: iteration  o: object

chdept += '~' + $(o).attr('id');

}

 

JQuery: Pro Tip Toggle Visibility

I’ve been coding with JQuery for a very long time, so I can’t believe I didn’t know this…

When I wanted to show/hide elements I would always use .is(:visible) and show or hide the object accordingly.

Yesterday, while looking for something else I found .toggle.

So:



$(this).toggle();

//will show or hide an element

I imagine a lot of you are thinking, “Well yeah…”

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.

JQuery: Add Rows and Columns to Tables Programmatically

This turned out to be a bit of a bear to search for exactly what I wanted, in such a way that I understood it…so I’m posting here.

The Problem

To create a table which the user could add columns or rows as they required.
New rows must contain the columns added earlier.

There is no requirement to isolate additional columns to specific rows.

The Solution

The example below uses a class selector as there are several tables (also added programmatically).

Adding a column.


$(".sbutc").click(function(e){
		
		var tid = this.id;
		var bid = tid.replace('sbutc_','stable_');   //This points to the appropriate parent table

                //first, I need to know how many rows there are so I can get the number of columns in the last one (skipping header rows)
                //Note that I point to the tbody object,  if you don't use these,  that should be the table id.

		var rows = document.getElementById(bid).getElementsByTagName("tbody")[0].getElementsByTagName("tr").length;
		

		var cols = $('#' + bid + ' tr:nth-child(' + rows + ') td').length;   //get's the number of columns in the last row
		console.log('cols: ' + cols);
		
		$("#" + bid).find('tr').each(function(){                            
						
                $(this).find('td').eq(cols-1).after('<td>new cell added</td>');      //adds the new cell. 
   		}); 

               /*
                You'll note that I subtract 1 from the column count when adding the column.  This is because when pulling the count, it starts with 1, while 
                object indexes always start at 0
               */

This adds the row.


$(".sbutr").click(function(e){
		
		var tid = this.id;
		var bid = tid.replace('sbutr_','stable_');
		var rows = document.getElementById(bid).getElementsByTagName("tbody")[0].getElementsByTagName("tr").length;
		var cols = $('#' + bid + ' tr:nth-child(' + rows + ') td').length; 
		
                
		
		var apstring = '<tr>';             //sets up the string used in the append statement
		
		for(var i=1;i<=cols;i++) {        //adds a td element for each row detected above and appends it to the apstring
			
			apstring += '<td ondrop="drop(event)" ondragover="allowDrop(event)">-</td>';
			
		}
		
		apstring += '</tr>';              //very important!
		
		$('#' + bid + ' > tbody:last').append(apstring);   //append the row to the bottom of the table
		
		
		
	});



I will post a link so you can see it in action when I get a chance (behind a firewall currently).

Web Design: Dynamic Tables with Clickable Content

My preferred method for building tables with dynamic content (search results, etc) is to do so in PHP.
The problem there is, how do I make it so the user can interact with my table data?

I do this using class and id within the appropriate tr/td tags, concatenating a row identifier to the id. This gives me the information I need to identify the rowset that the user wants to address.

When the user clicks on one of these elements, I use a class selector in JQUERY to capture the event, strip the known value, using string.replace from the element id, leaving me with the row identifier. This allows me to pass on the appropriate reference to whatever query I need to run.

Here’s an example:

php script

<?php
//do some query stuff and set up your table here
//Your db table contains the columns idx (your PK index), name, comment
$output = '<table>';
$output .= '<tr><td colspan="3">Click the name to do stuff!</td></tr>';
foreach($query as $row) {

 $output .= '<tr><td class="clickme" id="cm_'.$row['idx'].'">'.$row['name'].'</td><td>'.$row['comment'].'</td></tr>';
//                                        ^^^^^^^^^^^^^^^^    there's the concatenation bit                                      
}
$output .= '</table>';
echo $output

?>

JQuery function


$(".clickme").click(function(e) {

var tid = this.id;
var rid = tid.replace('cm_','');   //this leaves you with only the contents of the idx column of the database row for the clicked line

alert("Congrats! You clicked row index " + rid);

})

I’m certain that you would do something more useful than pop up an alert box (unless your users are easy to amuse and not all that productive)
Sometime soon I’ll post some comprehensive examples, such as how to bring up text boxes to edit the data (hint: I use visibility alot in that one!