Load a Bootstrap popover content with AJAX. Is this possible?

JqueryTwitter Bootstrap

Jquery Problem Overview


The appropriate bits of what I tried are here:

<a href="#" data-content="<div id='my_popover'></div>"> Click here </a>

$(".button").popover({html: true})

$(".button").click(function(){
	$(this).popover('show');
	$("#my_popover").load('my_stuff')
})

When I click, I see the request get made, but doesn't populate the popover. I don't even see HTML for the popover get added to the DOM, but that could be firebug.

Has anyone tried this?

Jquery Solutions


Solution 1 - Jquery

Works ok for me:

$('a.popup-ajax').popover({
	"html": true,
	"content": function(){
		var div_id =  "tmp-id-" + $.now();
		return details_in_popup($(this).attr('href'), div_id);
	}
});

function details_in_popup(link, div_id){
    $.ajax({
        url: link,
        success: function(response){
            $('#'+div_id).html(response);
		}
	});
    return '<div id="'+ div_id +'">Loading...</div>';
}

Solution 2 - Jquery

See my blog post for the working solution: https://medium.com/cagataygurturk/load-a-bootstrap-popover-content-with-ajax-8a95cd34f6a4

> First we should add a data-poload attribute to the elements you would > like to add a pop over to. The content of this attribute should be the > url to be loaded (absolute or relative):

<a href="#" title="blabla" data-poload="/test.php">blabla</a>

> And in JavaScript, preferably in a $(document).ready();

$('*[data-poload]').hover(function() {
    var e=$(this);
    e.off('hover');
    $.get(e.data('poload'),function(d) {
        e.popover({content: d}).popover('show');
    });
});

> off('hover') prevents loading data more than once and popover() binds > a new hover event. If you want the data to be refreshed at every hover > event, you should remove the off. > > Please see the working JSFiddle of the example.

Solution 3 - Jquery

Having read all these solutions, I think the solution becomes much simpler if you use a synchronous ajax call. You can then use something like:

  $('#signin').popover({
    html: true,
    trigger: 'manual',
    content: function() {
      return $.ajax({url: '/path/to/content',
                     dataType: 'html',
                     async: false}).responseText;
    }
  }).click(function(e) {
    $(this).popover('toggle');
  });

Solution 4 - Jquery

I have updated the most popular answer. But in case my changes will not be approved I put here a separate answer.

Differences are:

  • LOADING text shown while content is loading. Very good for slow connection.
  • Removed flickering which occures when mouse leaves popover first time.

First we should add a data-poload attribute to the elements you would like to add a pop over to. The content of this attribute should be the url to be loaded (absolute or relative):

<a href="#" data-poload="/test.php">HOVER ME</a>

And in JavaScript, preferably in a $(document).ready();

 // On first hover event we will make popover and then AJAX content into it.
$('[data-poload]').hover(
    function (event) {
        var el = $(this);

        // disable this event after first binding 
        el.off(event);

        // add initial popovers with LOADING text
        el.popover({
            content: "loading…", // maybe some loading animation like <img src='loading.gif />
            html: true,
            placement: "auto",
            container: 'body',
            trigger: 'hover'
        });

        // show this LOADING popover
        el.popover('show');

        // requesting data from unsing url from data-poload attribute
        $.get(el.data('poload'), function (d) {
            // set new content to popover
            el.data('bs.popover').options.content = d;

            // reshow popover with new content
            el.popover('show');
        });
    },
    // Without this handler popover flashes on first mouseout
    function() { }
);

off('hover') prevents loading data more than once and popover() binds a new hover event. If you want the data to be refreshed at every hover event, you should remove the off.

Please see the working JSFiddle of the example.

Solution 5 - Jquery

IN 2015, this is the best answer

$('.popup-ajax').mouseenter(function() {
   var i = this
   $.ajax({
      url: $(this).attr('data-link'), 
      dataType: "html", 
      cache:true, 
      success: function( data{
         $(i).popover({
            html:true,
            placement:'left',
            title:$(i).html(),
            content:data
         }).popover('show')
      }
   })
});

$('.popup-ajax').mouseout(function() {
  $('.popover:visible').popover('destroy')
});

Solution 6 - Jquery

A variation of the code from Çağatay Gürtürk, you could use the delegate function instead and force hiding the popover on hoverout.

$('body').delegate('.withajaxpopover','hover',function(event){
    if (event.type === 'mouseenter') {
		var el=$(this);
		$.get(el.attr('data-load'),function(d){
			el.unbind('hover').popover({content: d}).popover('show');
		});
    }  else {
		$(this).popover('hide');
	}
});

Solution 7 - Jquery

The solution of Çağatay Gürtürk is nice but I experienced the same weirdness described by Luke The Obscure:

When ajax loading lasts too much (or mouse events are too quick) we have a .popover('show') and no .popover('hide') on a given element causing the popover to remain open.

I preferred this massive-pre-load solution, all popover-contents are loaded and events are handled by bootstrap like in normal (static) popovers.

$('.popover-ajax').each(function(index){

	var el=$(this);
	
	$.get(el.attr('data-load'),function(d){
        el.popover({content: d});   	
    });		

});

Solution 8 - Jquery

Another solution:

$target.find('.myPopOver').mouseenter(function()
{
	if($(this).data('popover') == null)
	{
		$(this).popover({
			animation: false,
			placement: 'right',
			trigger: 'manual',
			title: 'My Dynamic PopOver',
			html : true,
			template: $('#popoverTemplate').clone().attr('id','').html()
		});
	}
	$(this).popover('show');
	$.ajax({
		type: HTTP_GET,
		url: "/myURL"

		success: function(data)
		{
			//Clean the popover previous content
			$('.popover.in .popover-inner').empty();	

			//Fill in content with new AJAX data
			$('.popover.in .popover-inner').html(data);

		}
	});
	
});

$target.find('.myPopOver').mouseleave(function()
{
	$(this).popover('hide');
});

The idea here is to trigger manually the display of PopOver with mouseenter & mouseleave events.

On mouseenter, if there is no PopOver created for your item (if($(this).data('popover') == null)), create it. What is interesting is that you can define your own PopOver content by passing it as argument (template) to the popover() function. Do not forget to set the html parameter to true also.

Here I just create a hidden template called popovertemplate and clone it with JQuery. Do not forget to delete the id attribute once you clone it otherwise you'll end up with duplicated ids in the DOM. Also notice that style="display: none" to hide the template in the page.

<div id="popoverTemplateContainer" style="display: none">

	<div id="popoverTemplate">
		<div class="popover" >
			<div class="arrow"></div>
			<div class="popover-inner">
				//Custom data here
			</div>
		</div>
	</div>
</div>

After the creation step (or if it has been already created), you just display the popOver with $(this).popover('show');

Then classical Ajax call. On success you need to clean the old popover content before putting new fresh data from server. How can we get the current popover content ? With the .popover.in selector! The .in class indicates that the popover is currently displayed, that's the trick here!

To finish, on mouseleave event, just hide the popover.

Solution 9 - Jquery

There are way too many answers here but I also found none of them to be what I wanted. I've extended Ivan Klass's answer to be both Bootstrap 4 appropriate and intelligently cached.

Note that the snippet won't actually load the remote address due to Stackoverflow's CORS policy.

var popoverRemoteContents = function(element) {
  if ($(element).data('loaded') !== true) {
    var div_id = 'tmp-id-' + $.now();
    $.ajax({
      url: $(element).data('popover-remote'),
      success: function(response) {
        $('#' + div_id).html(response);
        $(element).attr("data-loaded", true);
        $(element).attr("data-content", response);
        return $(element).popover('update');
      }
    });
    return '<div id="' + div_id + '">Loading...</div>';
  } else {
    return $(element).data('content');
  }
};

$('[data-popover-remote]').popover({
  html: true,
  trigger: 'hover',
  content: function() {
    return popoverRemoteContents(this);
  }
});

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet"/>

<span data-popover-remote="http://example.com/">Remote Popover test with caching</span>

Solution 10 - Jquery

Here is my solution which works fine with ajax loaded content too.

/*
 * popover handler assigned document (or 'body') 
 * triggered on hover, show content from data-content or 
 * ajax loaded from url by using data-remotecontent attribute
 */
$(document).popover({
	selector: 'a.preview',
	placement: get_popover_placement,
	content: get_popover_content,
	html: true,
	trigger: 'hover'
});

function get_popover_content() {
	if ($(this).attr('data-remotecontent')) {
		// using remote content, url in $(this).attr('data-remotecontent')
		$(this).addClass("loading");
		var content = $.ajax({
			url: $(this).attr('data-remotecontent'),
			type: "GET",
			data: $(this).serialize(),
			dataType: "html",
			async: false,
			success: function() {
				// just get the response
			},
			error: function() {
				// nothing
			}
		}).responseText;
		var container = $(this).attr('data-rel');
		$(this).removeClass("loading");
		if (typeof container !== 'undefined') {
			// show a specific element such as "#mydetails"
			return $(content).find(container);
		}
		// show the whole page
		return content;
	}
	// show standard popover content
	return $(this).attr('data-content');
}

function get_popover_placement(pop, el) {
	if ($(el).attr('data-placement')) {
		return $(el).attr('data-placement');
	}
    // find out the best placement
    // ... cut ...
	return 'left';
}

Solution 11 - Jquery

If the content in the popover isn't likely to change, it would make sense to retrieve it only once. Also, some of the solutions here have the issue that if you move over multiple "previews" fast, you get multiple open popups. This solution addresses both those things.

$('body').on('mouseover', '.preview', function() 
{
    var e = $(this);
    if (e.data('title') == undefined)
    {
        // set the title, so we don't get here again.
        e.data('title', e.text());

        // set a loader image, so the user knows we're doing something
        e.data('content', '<img src="/images/ajax-loader.gif" />');
        e.popover({ html : true, trigger : 'hover'}).popover('show');

        // retrieve the real content for this popover, from location set in data-href
        $.get(e.data('href'), function(response)
        {
            // set the ajax-content as content for the popover
            e.data('content', response.html);

            // replace the popover
            e.popover('destroy').popover({ html : true, trigger : 'hover'});

            // check that we're still hovering over the preview, and if so show the popover
            if (e.is(':hover'))
            {
                e.popover('show');
            }
        });
    }
});

Solution 12 - Jquery

I think my solution is more simple with default functionality.

http://jsfiddle.net/salt/wbpb0zoy/1/

$("a.popover-ajax").each(function(){
		 $(this).popover({
			trigger:"focus",
			placement: function (context, source) {
                  var obj = $(source);
				  $.get(obj.data("url"),function(d) {
                        $(context).html( d.titles[0].title)
                  });	
			},
			html:true,
			content:"loading"
		 });
});

<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/js/bootstrap.min.js"></script>


<ul class="list-group">
  <li class="list-group-item"><a href="#" data-url="https://tr.instela.com/api/v2/list?op=today" class="popover-ajax">Cras justo odio</a></li>
  <li class="list-group-item"><a href="#" data-url="https://tr.instela.com/api/v2/list?op=today" class="popover-ajax">Dapibus ac facilisis in</a></li>
  <li class="list-group-item"><a href="#" data-url="https://tr.instela.com/api/v2/list?op=today" class="popover-ajax">Morbi leo risus</a></li>
  <li class="list-group-item"><a href="#" data-url="https://tr.instela.com/api/v2/list?op=today" class="popover-ajax">Porta ac consectetur ac</a></li>
  <li class="list-group-item"><a href="#" data-url="https://tr.instela.com/api/v2/list?op=today" class="popover-ajax">Vestibulum at eros</a></li>
</ul>

Solution 13 - Jquery

an answer similar to this has been given in this thread: https://stackoverflow.com/questions/8067321/setting-data-content-and-displaying-popover - it is a way better way of doing what you hope to achieve. Otherwise you will have to use the live: true option in the options of the popover method. Hopefully this helps

Solution 14 - Jquery

I tried the solution by Çağatay Gürtürk but got the same weirdness as Luke the Obscure. Then tried the solution by Asa Kusuma. This works, but I believe it does the Ajax read every time the popover is displayed. The call to unbind('hover') has no effect. That's because delegate is monitoring for events in a specific class -- but that class is unchanged.

Here's my solution, closely based on Asa Kusuma's. Changes:

  • Replaced delegate with on to match new JQuery libraries.
  • Remove 'withajaxpopover' class rather than unbinding hover event (which was never bound)
  • Add "trigger: hover" to the popover so that Bootstrap will handle it completely beginning with the second use.
  • My data loading function returns JSon, which makes it easy to specify both the title and the content for the popover.

/*  Goal: Display a tooltip/popover where the content is fetched from the
application the first time only.

    How:  Fetch the appropriate content and register the tooltip/popover the first time 
          the mouse enters a DOM element with class "withajaxpopover".  Remove the 
          class from the element so we don't do that the next time the mouse enters.
          However, that doesn't show the tooltip/popover for the first time
          (because the mouse is already entered when the tooltip is registered).
          So we have to show/hide it ourselves.
*/
$(function() {
  $('body').on('hover', '.withajaxpopover', function(event){
      if (event.type === 'mouseenter') {
          var el=$(this);
          $.get(el.attr('data-load'),function(d){
              el.removeClass('withajaxpopover')
              el.popover({trigger: 'hover', 
                          title: d.title, 
                          content: d.content}).popover('show');
          });
      }  else {
          $(this).popover('hide');
      }
  });
});

Solution 15 - Jquery

I tried some of the suggestions here and I would like to present mine (which is a bit different) - I hope it will help someone. I wanted to show the popup on first click and hide it on second click (of course with updating the data each time). I used an extra variable visable to know whether the popover is visable or not. Here is my code: HTML:

<button type="button" id="votingTableButton" class="btn btn-info btn-xs" data-container="body" data-toggle="popover" data-placement="left" >Last Votes</button>

Javascript:

$('#votingTableButton').data("visible",false);

$('#votingTableButton').click(function() {	
if ($('#votingTableButton').data("visible")) {
	$('#votingTableButton').popover("hide");
	$('#votingTableButton').data("visible",false);			
}
else {
	$.get('votingTable.json', function(data) {
		var content = generateTableContent(data);
		$('#votingTableButton').popover('destroy');
		$('#votingTableButton').popover({title: 'Last Votes', 
								content: content, 
								trigger: 'manual',
								html:true});
		$('#votingTableButton').popover("show");
		$('#votingTableButton').data("visible",true);	
	});
}	
});

Cheers!

Solution 16 - Jquery

Here is a way that addresses a few issues:

  1. Alignment issues after content is updated, especially if the placement is "top". The key is calling ._popper.update(), which recalculates the position of the popover.
  2. Width change after the content is updated. It doesn't break anything, it just looks jarring to the user. To lessen that, I set the width of the popover to 100% (which is then capped by the max-width).

var e = $("#whatever");
e.popover({
    placement: "top",
    trigger: "hover",
    title: "Test Popover",
    content: "<span class='content'>Loading...</span>",
    html: true
}).on("inserted.bs.popover", function() {
    var popover = e.data('bs.popover');
    var tip = $(popover.tip);
    tip.css("width", "100%");
    $.ajax("/whatever")
        .done(function(data) {
            tip.find(".content").text(data);
            popover._popper.update();
        }).fail(function() {
            tip.find(".content").text("Sorry, something went wrong");
        });
});

Solution 17 - Jquery

$("a[rel=popover]").each(function(){
		var thisPopover=$(this);
                var thisPopoverContent ='';
                if('you want a data inside an html div tag') {
		        thisPopoverContent = $(thisPopover.attr('data-content-id')).html();
                }elseif('you want ajax content') {
                    $.get(thisPopover.attr('href'),function(e){
                        thisPopoverContent = e;
                    });
            }
		$(this).attr(	'data-original-title',$(this).attr('title')	);
		thisPopover.popover({
			content: thisPopoverContent
		})
		.click(function(e) {
			e.preventDefault()
		});

	});

note that I used the same href tag and made it so that it doesn't change pages when clicked, this is a good thing for SEO and also if user doesn't have javascript!

Solution 18 - Jquery

I like Çağatay's solution, but I the popups were not hiding on mouseout. I added this extra functionality with this:

// hides the popup
$('*[data-poload]').bind('mouseout',function(){
   var e=$(this);
   e.popover('hide'); 
});

Solution 19 - Jquery

I used the original solution but made a couple of changes:

First, I used getJSON() instead of get() because I was loading a json script. Next I added the trigger behaviour of hover to fix the sticky pop over issue.

$('*[data-poload]').on('mouseover',function() {
    var e=$(this);
    $.getJSON(e.data('poload'), function(data){
        var tip;
        $.each(data, function (index, value) {
           tip = this.tip;
           e.popover({content: tip, html: true, container: 'body', trigger: 'hover'}).popover('show');
        });
    });
});

Solution 20 - Jquery

I added html: true, so it doesn't show raw html output, in case you want to format your results. You can also add in more controls.

	$('*[data-poload]').bind('click',function() {
		var e=$(this);
		e.unbind('click');
		$.get(e.data('poload'),function(d) {
			e.popover({content: d, html: true}).popover('show', {
				
			});
		});
	});

Solution 21 - Jquery

Display ajax popover on static element with hover trigger:

$('.hover-ajax').popover({
    "html": true,
    trigger: 'hover',
    "content": function(){
        var div_id =  "tmp-id-" + $.now();
        return details_in_popup($(this).attr('href'), div_id);
    }
});

function details_in_popup(link, div_id){
    $.ajax({
        url: link,
        success: function(response){
            $('#'+div_id).html(response);
        }
    });
    return '<div id="'+ div_id +'">Loading...</div>';
}

Html :

<span class="hover-ajax" href="http://domain.tld/file.php"> Hey , hoover me ! </span>

Solution 22 - Jquery

  $('[data-poload]').popover({
    content: function(){
      var div_id =  "tmp-id-" + $.now();
      return details_in_popup($(this).data('poload'), div_id, $(this));
    },
    delay: 500,
    
    trigger: 'hover',
    html:true
  });
  
  function details_in_popup(link, div_id, el){
      $.ajax({
          url: link,
          cache:true,
          success: function(response){
              $('#'+div_id).html(response);
              el.data('bs.popover').options.content = response;
          }
      });
      return '<div id="'+ div_id +'"><i class="fa fa-spinner fa-spin"></i></div>';
  }   

Ajax content is loaded once! see el.data('bs.popover').options.content = response;

Solution 23 - Jquery

I did and it's work perfect with ajax and loading on popover content.

var originalLeave = $.fn.popover.Constructor.prototype.leave;
		$.fn.popover.Constructor.prototype.leave = function(obj){
			var self = obj instanceof this.constructor ?
		    	obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type)
		  	var container, timeout;

		  	originalLeave.call(this, obj);

		  	if(obj.currentTarget) {
			    container = $(obj.currentTarget).siblings('.popover')
			    timeout = self.timeout;
			    container.one('mouseenter', function(){
			    	//We entered the actual popover – call off the dogs
			      	clearTimeout(timeout);
			      	//Let's monitor popover content instead
			      	container.one('mouseleave', function(){
			        	$.fn.popover.Constructor.prototype.leave.call(self, self);
			      	});
			    })
		  	}
		};
		var attr = 'tooltip-user-id';
		if ($('a['+ attr +']').length)
			$('a['+ attr +']').popover({
			    html: true,
			    trigger: 'click hover',
			    placement: 'auto',
			    content: function () {
			    	var this_ = $(this);
			    	var userId = $(this).attr(attr);
			    	var idLoaded = 'tooltip-user-id-loaded-' + userId;
		        	var $loaded = $('.' + idLoaded);
		        	if (!$loaded.length) {
			    		$('body').append('<div class="'+ idLoaded +'"></div>');
			    	} else if ($loaded.html().length) {
			    		return $loaded.html();
			    	}
			        $.get('http://example.com', function(data) {
				    	$loaded.html(data);
				    	$('.popover .popover-content').html(data);
				    	this_.popover('show');
					});
					return '<img src="' + base_url + 'assets/images/bg/loading.gif"/>';
			    },
			    delay: {show: 500, hide: 1000},
			    animation: true
			});

You can check it out http://kienthuchoidap.com. Goto this and hover to username of user.

Solution 24 - Jquery

<button type="button" id="popover2" title="" data-content="<div id='my_popover' style='height:250px;width:300px;overflow:auto;'>Loading...Please Wait</div>" data-html="true" data-toggle="popover2" class="btn btn-primary" data-original-title="A Title">Tags</button>

$('#popover2').popover({ 
    html : true,
    title: null,
    trigger: "click",
    placement:"right"
});

$("#popover2").on('shown.bs.popover', function(){
    $('#my_popover').html("dynamic content loaded");

});

Solution 25 - Jquery

For me works change data-content befora load popover:

$('.popup-ajax').data('content', function () {
    var element = this;
    $.ajax({
        url: url,
        success: function (data) {
            
            $(element).attr('data-content', data)

            $(element).popover({
                html: true,
                trigger: 'manual',
                placement: 'left'
            });
            $(element).popover('show')
        }})
})

Solution 26 - Jquery

This works for me, this code fix possibles alignment issues:

<a class="ajax-popover" data-container="body" data-content="Loading..." data-html="data-html" data-placement="bottom" data-title="Title" data-toggle="popover" data-trigger="focus" data-url="your_url" role="button" tabindex="0" data-original-title="" title="">
  <i class="fa fa-info-circle"></i>
</a>

$('.ajax-popover').click(function() {
  var e = $(this);
  if (e.data('loaded') !== true) {
    $.ajax({
      url: e.data('url'),
      dataType: 'html',
      success: function(data) {
        e.data('loaded', true);
        e.attr('data-content', data);
        var popover = e.data('bs.popover');
        popover.setContent();
        popover.$tip.addClass(popover.options.placement);
        var calculated_offset = popover.getCalculatedOffset(popover.options.placement, popover.getPosition(), popover.$tip[0].offsetWidth, popover.$tip[0].offsetHeight);
        popover.applyPlacement(calculated_offset, popover.options.placement);
      },
      error: function(jqXHR, textStatus, errorThrown) {
        return instance.content('Failed to load data');
      }
    });
  }
});

Just in case, the endpoint I'm using returns html (a rails partial)

I took some part of the code from here https://stackoverflow.com/a/13565154/3984542

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionCambridgeMikeView Question on Stackoverflow
Solution 1 - JqueryIvan KlassView Answer on Stackoverflow
Solution 2 - JqueryÇağatay GürtürkView Answer on Stackoverflow
Solution 3 - JqueryConfusionView Answer on Stackoverflow
Solution 4 - JqueryAlexander CView Answer on Stackoverflow
Solution 5 - JqueryDorian MargineanuView Answer on Stackoverflow
Solution 6 - JqueryAsa KusumaView Answer on Stackoverflow
Solution 7 - JqueryfustakiView Answer on Stackoverflow
Solution 8 - JquerydoanduyhaiView Answer on Stackoverflow
Solution 9 - JqueryArchonicView Answer on Stackoverflow
Solution 10 - JquerydrillingmanView Answer on Stackoverflow
Solution 11 - JquerytowrView Answer on Stackoverflow
Solution 12 - JquerySalt HareketView Answer on Stackoverflow
Solution 13 - JqueryE StevenView Answer on Stackoverflow
Solution 14 - JquerybwbeckerView Answer on Stackoverflow
Solution 15 - JqueryItayBView Answer on Stackoverflow
Solution 16 - JqueryGabriel LuciView Answer on Stackoverflow
Solution 17 - JqueryNeoView Answer on Stackoverflow
Solution 18 - JqueryMinoView Answer on Stackoverflow
Solution 19 - JqueryMark FlavinView Answer on Stackoverflow
Solution 20 - JqueryWarren LandisView Answer on Stackoverflow
Solution 21 - JqueryAlin RazvanView Answer on Stackoverflow
Solution 22 - JquerySirCumzView Answer on Stackoverflow
Solution 23 - JqueryHo Thanh BinhView Answer on Stackoverflow
Solution 24 - JqueryShankar GuptaView Answer on Stackoverflow
Solution 25 - JqueryThiago BussikiView Answer on Stackoverflow
Solution 26 - Jqueryvicente.favaView Answer on Stackoverflow