jQuery

typeahead multiple sources

Posted on: March 2nd, 2014 by taff No Comments

 

Today I would like to continue the series on by going into retrieving multiple sources with typeahead. I recently went into how to limit the results with typeahead. This example goes into getting more than one dataset into your result. As I mentioned in the first post, I have two types of data one that retrieves the searchterms other users have used and the other to find relevant products in a database so lets look at retrieving both sources with a single call.

Retrieving multiple sources with typeahead

The example below shows how to retrieve multiple sources with typeahead. To assist the user with seeing where to suggestions are coming from, we have added a header parameter which is displayed above the dataset thus increasing legibility.

jQuery('#Search').typeahead([
{
limit: 3,
name: 'searchterms',
remote: '/searchterms.php?q=%QUERY',
header: '<h3 class="suggest-elements">Search Terms</h3>'
},
{
limit: 5,
name: 'products',
remote: /products.php?q=%QUERY,
header: '<h3 class="suggest-elements">Products</h3>'
}
]);

Note that we can individually set the number of results when retrieving multiple sources with typeahead. The example above collects 3 results from the searchterms query and five results from the products query. The datasets are separated with the respective headers. In the next tutorial we will go into using a custom template to directly link to the products page. The searchterms dataset will functionally stay the same, so that it simply changes the input field upon selection and fires the query.

Loop through Input Elements in a DIV Tag with jQuery

Posted on: February 26th, 2014 by taff 2 Comments

 

Occasionally you need to loop through input elements prior to submission so that you can see what exactly is being submitted.
I like to use jQuery, the javascript framework of my choice for this. Although the title describes looping through input elements in a DIV Tag, you can use the following script to equally loop through elements in a FORM tag identically.

The following script will loop through input elements in the DIV tag with the ID nameOfDiv. You can, of course, use a different selector if you need the elements in multiple divs.

var $inputs = jQuery('#nameOfDiv :input');
var values = {};
$inputs.each(function() {
    console.log(values[this.name] = jQuery(this).val());
});
jQuery('#nameOfDiv').submit();

Using the jQuery each function we can loop through all the input elements in our div. For the example, I am simply outputting them into the console window, i.e. Firebug or the Chrome console.

 

This is a short entry on how to update jQuery's Slider immediately from an input field whenever it changes. There are quite a lot of events that we need to catch. The normal change event just doesn't cut it as it only fires when the the input field looses its focus. To allow us to update the jQuery Slider immediately, we need to use the keyup event. Every time a key is released the values of our field are immediately sent to the jQuery Slider. The other events include the input event which fires when the interface changes the value of our field. Because of Internet Explorer, which is buggy with this event, we have also added propertychange. When the cut and paste events trigger probably comes as no surprise.

Updating jQuery Slider Value immediately upon Input Change

jQuery( ".myInputs" ).bind("propertychange keyup input cut paste", function(event){
        jQuery( "#slider-id" ).slider( "values", [ jQuery( "#minimumValue" ).val(), jQuery( "#maximumValue" ).val() ] );
    });

We have bound the event to the elements with the class myInputs, in this case our input fields for the minimum and the maximum values. Whenever one or more of the events is triggered, the jQuery Slider values (I have a minimum and a maximum value) are updated with the values of our input fields. We don't have to loose focus for the slider to update, thanks to our keyup event. Marking the contents of a field and cutting it out or pasting content also triggers events mentioned above. All in all a sound solution to the problem.

jquery session cookie – HTML5 sessionStorage

Posted on: November 5th, 2013 by taff No Comments

 

I've always been a bit reluctant to using HTML5 that isn't globally supported, but recently I've been doing a lot of work on a mobile version of a website which means I get to use everything :-)

Whenever I used to need a jquery session cookie, i.e. a cookie that exists for a session and is accessible via javascript, I would use the excellent jQuery cookie plugin but with the (near) global support for sessionStorage and localStorage I think it will become a thing of the past.

sessionStorage - The HTML5 equivalent of a jquery session cookie

I needed a jquery session cookie to see if someone had already had the geolocation window and if so, surpress it until the next time the user visits the site. I could probably have done this just as quick with the cookie plugin but after taking a look at the sessionStorage support, decided it was the way to go.

jQuery(function () {
var hadLocationWindow = sessionStorage.getItem("hadLocationWindow");

if(hadLocationWindow == null || hadLocationWindow == 'undefined') {
sessionStorage.setItem("hadLocationWindow", "YES");
console.log("no location yet, offer geolocation");
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(showPosition);
}
} else {
console.log("you have seen this window before");
}

});

Viewing SessionStorage and localStorage Data

When it comes to sessionStorage and localStorage (the persistent version of storage), I use a firebug with a simple


console.log(sessionStorage);

normally to see what is happening. If I need to do more I can recommend the FireStorage Plus! Plugin

Another advantage is the ability to save large amounts of data which has no limit to the possibilities such as saving profile data to save querying the database so often thus making it even more useful than the jquery session cookie

jQuery change url parameter value

Posted on: September 7th, 2013 by taff 2 Comments

 

Using jQuery to change the parameter of a url when an element, such as a select or a is clicked, can be done in a number of ways. Below are two examples.

Change URL parameter value by using the javascript split method

The simplest is probably something along these lines, although as we ill see later, the easiest is not always the best.

function changeFirstParam(href, newVal) {
//get our parameters into an array
params = href.split('&');
//this will only work if the first parameter is the one
//we need to change
var src = params[0].split('=');
//Remove the first value of the first parameter
params.shift();
//Give the first parameter a new value
src[1] = newVal;
//Join it all back up
var newUrl = ( src.join('=') + params.join('&'));
//Return our new url
return newUrl;
}

var href = changeFirstParam("http://domain.com?var=thisIsOld&a=1&b=2&c=3","theNewValue");
console.log(href);

The above script splits the parameters into an array, then changes the first parameters value. This will probably suffice for most cases but what if we aren't sure which position our parameter will have? I want to keep my scripts as dynamic as possible to accomodate future changes in the backend, thus even though the overhead is slightly higher I prefer something with a regular expression.

Change URL parameter value with a Javascript Regular Expression (RegEx)

function changeParam(href, newVal) {
var tmpRegex = new RegExp("(var=)[a-z]+", 'ig');
return replace(tmpRegex, '$1'+newVal);
}

var href = changeParam("http://domain.com?var=thisIsOld&bca=something&b=2&c=3","theNewValue");
console.log(href);

This will simply replace the value of our var parameter no matter what position it has in the parameter list. Not bad, but what if I need an identical function when a radio button value is changed as well. The solution of course? A variable! This is why the above example uses a RegExp constructor. If we had tried to put a variable directly in the replace method it wouldn't work.

Change URL parameter value with a variable in a Javascript Regular Expression (RegEx)

function changeParamByName(href, paramName, newVal) {
var tmpRegex = new RegExp("(" + paramName + "=)[a-z]+", 'ig');
return href.replace(tmpRegex, '$1'+newVal);
}

var href = changeParamByName("http://domain.com?var=thisIsOld&bca=something&b=2&c=3","bca","theNewValue");
console.log(href);

The following is an example of some html where I used the following script. It is a simple ul list whereby the list element has a data-language attribute. When someone clicks on a list element, we want the favLanguage parameter value to change accordingly:

Change URL Parameter Value when Element clicked with jQuery

<ul id="language">
	<li data-language="php">PHP</li>
	<li data-language="asp">ASP</li>
	<li data-language="js">Javascript</li>
</ul>
<a id="languageLink" href="http://domain.com/index.php?favLanguage=default">Submit Language</a>
var paramName = "favLanguage";
jQuery("#language li").click( function(e) {
jQuery("#languageLink").attr('href', function(i,a){
var tmpRegex = new RegExp("(" + paramName + "=)[a-z]+", 'ig');
return a.replace(tmpRegex, '$1'+e.target.dataset.language);
});
});

We've done away with an external function now, which should increase the readability, although if we needed the functionality on a different element too, we would outsource it. When an item from the list is clicked the href attribute is changed.

Resize iframe from another domain with easyXDM

Posted on: June 23rd, 2013 by taff No Comments

 

I recently ran into the problem of trying to resize an iframe element to match the height of the content. This does away with extra scrollbars which can create usability issues.
Unfortunately trying to resize iframe from another domain is not an easy task because of the same origin policy. However, there is normally a workaround for all things web and this is the solution I implemented to allow me to resize an iframe from another domain.

Although there are various ways to workaround the entire ajax / same origin policy headache I went with easyXDM and followed the resize iframe based on content example. The example worked as described but I then noticed the dreaded disclaimer "If you plan on navigating the inner window, be aware that this will break the connection and subsequent pages won’t cause the iframe to resize" and indeed this was the case. The suggested workaround was to use an intermediate iframe and an example was provided. Either this wasn't very well documented or I just didn't find it, so here is how I managed to resize iframe from another domain and navigate within it.

Document with the iframe

The document with the iframe had been built using JSF in this example.
The value of my hidden field with the id statisticsURL had been declared in a config file and was something like "http://www.someOtherDomainThanThisOne.com/page1.html"
The message being passed is the height of the content. I added 50 to the total height to ensure that scrollbars were not shown.

<form><input id="statisticsURL" type="hidden" value="#{sessionBean.statisticsURL}" /></form><script type="text/javascript">// <!&#91;CDATA&#91;
   var pageURL = encodeURIComponent($("#statisticsURL").val()); 			
   var transport = new easyXDM.Socket({ 				
      remote: "/iframe-intermediate.html?url="+pageURL, 				
      container: "iframeContainer", 				
      onMessage: function(message, origin){ 					
        message = (Number(message)+50); 					
        this.container.getElementsByTagName("iframe")&#91;0&#93;.style.height = message + "px"; 					
// &#93;&#93;></script>
<div id="iframeContainer"></div>

Intermediate iFrame to allow navigation from within the iframe and still be able to resize

Our intermediate iFrame is hosted at the same domain as our iFrame content i.e. www.someOtherDomainThanThisOne.com
In the example above it is called iframe-intermediate.html but the name plays no role whatsoever. The content of the intermediate iframe is:

<head>
        <script type="text/javascript" src="/path/to/easyXDM.min.js"></script>
        <script type="text/javascript">
            var iframe;
            var socket = new easyXDM.Socket({
                swf : "/path/to/easyxdm.swf",
                onReady : function() {
                    iframe = document.createElement("iframe");
                    iframe.frameBorder = 0;
                    document.body.appendChild(iframe);
                    iframe.src = easyXDM.query.url;

                    var timer;
                    iframe.onload = function() {
                        var d = iframe.contentWindow.document;
                        var originalHeight = d.body.clientHeight || d.body.offsetHeight || d.body.scrollHeight;

                        // We want to monitor the document for resize events in case of the use of accordions and such,
                        // but unfortunately only the window node emits the resize event, and we need the body's.
                        // The only solution then is to use polling..

                        // Lets start the polling if not all ready started
                        if(!timer) {
                            timer = setInterval(function() {
                                try {
                                    var d = iframe.contentWindow.document;
                                    var newHeight = d.body.clientHeight || d.body.offsetHeight || d.body.scrollHeight;
                                    if(newHeight != originalHeight) {
                                        // The height has changed since last we checked
                                        originalHeight = newHeight;
                                        socket.postMessage(originalHeight);
                                    }
                                } catch(e) {
                                    // We tried to read the property at some point when it wasn't available
                                }
                            }, 300);
                        }
                        // Send the first message
                        socket.postMessage(originalHeight);
                    };
                },
                onMessage : function(url, origin) {
                    iframe.src = url;
                }
            });

        </script>
        <style type="text/css">
            html, body {
                overflow: hidden;
                margin: 0px;
                padding: 0px;
                width: 100%;
                height: 100%;
            }
            iframe {
                width: 100%;
                height: 100%;
                border: 0px;
            }
        </style>
    </head>
    <body></body>

iFrame Content Example

This is example content to resize Iframe from another domain. The actual content of the iframe doesn't matter at all as in the example provided on the easyXDM website.

    <head>
        <title>easyXDM</title>
        <style type="text/css">
            html, body {
                overflow: hidden;
                margin: 0px;
                padding: 0px;
                background-color: green;
            }
        </style>
    </head>
    <body>
        <a href="resized_iframe_2.html">resized_iframe_2.html</a>
        <br/>
        Nam nulla nibh, tempus ut dictum eget, euismod vitae metus. Donec vitae nulla nec quam sagittis gravida vel quis eros. Nullam vel est justo. Donec euismod interdum magna, et rutrum libero tincidunt vel. Praesent imperdiet, magna et suscipit facilisis, nulla justo consequat nisl, et mollis elit nunc a est. Sed felis quam, condimentum eget gravida non, semper non quam. Duis vestibulum sem id erat tristique eleifend. Phasellus ante nunc, pulvinar nec facilisis at, hendrerit sed leo. Morbi lacinia nisl id nunc faucibus lacinia. Curabitur adipiscing leo a odio aliquet hendrerit. Nullam laoreet pulvinar suscipit.
    </body>

I spent a while trying to resize iframe from another domain until I finally managed to get it to work, so hopefully these examples will give you a good starter to workaround the same origin policy when you need to resize an iframe.

jquery each last iteration

Posted on: June 22nd, 2013 by taff No Comments

 

Rainer Sturm  / pixelio.de

Rainer Sturm / pixelio.de

I occasionally need to add some extra markup when looping through elements using jQuery each. The following is an example of some Javascript which I used to parse XML data that I received from an AJAX call. To cut down on overhead I don't use jquery .size() but prefered to use the "standard" .length property.

Get the last iteration of an each loop

The idea is simple to get the last iteration in the each loop, we simply find out how many elements we have in our array, loop through them, add one to our "counting" variable or incremental and check to see if we have reached the value of .length.

The example looks like this:

//get the length of our array
var totalLen = $(this).find('filename').length;

var tmpLen = 0;

$(this).find('filename').each(function(){
//add one each time the function is called
tmpLen++;
//add the content of our filename node
str += $(this).text();
//if it's the last element add a full stop, otherwse add a comma.
if(tmpLen<=totalLen){
str += ".";
}else{
str += ", ";
}
});

jQuery – Remove last row from table

Posted on: June 10th, 2013 by taff No Comments

 

Learning how to remove last row from table with javascript is functionality I occasionally implement when the last row contains totals for each column and I need to load more rows of data via ajax. I will delete the last table row then append data then call my total generator function.

If using jQuery I simply use the following to delete the last row from a table:

$('#idOfTable tr:last').remove();

Of late, whenever I use a table to display data I take advantage of the tablesorter plugin as it offers everything I need straight out of the box. The markup required by tablesorter for a table looks like this

<table>
<thead>
<tr>
<th>Column 1</th>
<th>Column 2</th>
</tr>
</thead>
<tbody>
<tr>
<td>Column 1</td>
<td>Column 2</td>
</tr>
<tr>
<td>Column 1</td>
<td>Column 2</td>
</tr>
</tbody>
<tfoot>
<tr>
<td>Footer 1</td>
<td>Footer 2</td>
</tr>
</tfoot>
</table>

As you can see I use the thead, tbody and tfoot tags. I think these are a good choice anyway so tablesorters requirement makes no difference to me at all.

Remove tfoot with jQuery

If I need to remove the entire tfoot before adding the new table rows it is even easier than the above script to remove a row. I can simply do

$('#idOfTable tbody').remove();

And it's bye bye tfoot.

 

I used the excellent jQuery tablesorter plugin yesterday to allow me to sort statistics being displayed in a table. The requirement was to be able to sort and export data in the currently sorted order to an Excel table. My method involved binding a function to the event when sorting ended. A simple

$("#idOfTable").tablesorter();

provided me with basic functionality and I was amazed at how fast the data was sorted. Excellent! the next stage was to restrict sorting so that one column could not be used to sort data. A simple update to

$("#idOfTable").tablesorter({
headers: {
2: {
sorter: false
}
}
});

This deactivates the header in the third column (the counter starts at 0).

Now the client wanted the ability to link and save sorted by a specific field.

The initial sort was carried out by the backend which, in this case was done in XSL.















We bind our function to manipulate the href of our export link (to add the parameters for the current sort order) as such:

$("#countries").bind("sortEnd",function() {
$('#countries thead tr th').each(
function(a){
var index=$(this).index();
var sortUp=$(this).is('.headerSortUp');
var sortDown=$(this).is('.headerSortDown');
var columnName = $(this).attr("name").toString().toLowerCase();
//Look to see which column currently has the sorting
if((sortUp == true)||(sortDown == true)){
switch(columnName){
case "country":
var columnSortName = "country";
break;
case "subscriber":
var columnSortName = "subscriber";
break;
case "total":
var columnSortName = "total";
break;
}
//Look to see which direction is currently being sorted
if(sortUp == true){
var sortDir = "&direction=descending"
}else if(sortDown == true){
var sortDir = "&direction=ascending"
}
var hashedURL="http://www.domain.com/exportLink?"
countriesParams = sortDir+"&countriesSort="+columnSortName;
//Change the href of our export link
$("#exportLnk").attr("href",hashedURL+countriesParams);
}
}
);
});

The function above is bound to the sortEnd Event provided by the tablesorter plugin, meaning that anytime the table is sorted the function is executed.
I'm using the classes added to the headers by tablesorter to ascertain whether the sort direction is ascending or descending. Using the .each loop I can also find out which column is being sorted by. This required a slight change to my normal table markup by adding a name attribute to the table header. the last stage rewrites the href of the URL to point to our export page with the current sort parameters. Simples

JQuery colour alternate table rows

Posted on: June 7th, 2013 by taff No Comments

 

Colouring alternate table rows increases readability, thus increasing usability. In particular long table rows with the same background colour being hard to read is a phenomenon that most of us know well from using MS Excel. The same goes for long tables in our browser where, in a worst case, we need to scroll the entire view.

Using jQuery to colour alternate table rows may sound strange when CSS now offers exactly that with the use of a pseudo selector.

Colour alternate table rows with CSS pseudo selector

tr:nth-child(even) {
background-color: #f8f8f8;
}

Unfortunately, and probably not that surprising for most of you, Internet Explorer 8 doesn't like the css solution. I am currently building an MIS for a large company and their browser of choice at the moment is, yes you guessed it, IE8 so I had to resort to a javascript solution. JQuery was already in use so I simply did the following

Colour alternate table rows with jQuery

$("tr:even").css("background-color", "#f8f8f8");

If I for whatver reason have no default background colour for my table rows I can use a short hand version of the if / else conditional like this

$("#idOgTable tbody tr").css("background-color", function(index) {
return index%2==0?"#f8f8f8":"#ffffff";
});

Due to my table setup using thead, tbody and tfoot tags I have the tbody in the selector. I needed this setup to allow me to use the amazing tablesorter plugin to exclude rows when sorting.

I hope you can use the above script to colour alternate table rows with jQuery.