One Link, Many Paths, Clicking Choice! (MultiLink, Part 1)

Part 2, and Part 3 are now up!

A call to arms, of sorts…

Clickers Divide!  Be free of the tyranny of only having one choice of where to go!

For many years, I’ve wanted an easy means to provide more than one possible target for a link.  In some ways, you could think of this as a menu, or a tooltip, but more specific.

[for the impatient, a demo: MultiLink Demo]

I want to click on a link, and have an option to go to one of several places.  Content authors should have a means of providing, say, links that go to a summary vs in-depth, or to easy vs hard, or to one of many languages.

I want to click on this:

And see this:

Sure, there are hacks to do this, but I see something in HTML5 that opens the door wide…

HTML5 Data Attributes

With HTML5, you can add data to any HTML element by using an attribute that starts with “data-“.  So far so good.  I could say this in HTML:

</pre>
<ul>
  <li id="listItem20" data-nickname="bucky"
      data-state="california">Daniel</li>
</ul>
<pre>

And in jQuery I would use:

// grab some data we attached to a list element
var myNickname = $('#listItem20').data('nickname');
var myFaveState= $('#listItem20').data('state');

Ok, so knowing this, there are several ways I could go about attaching data to an anchor (“<a>”) tag. First off, I could toss a bunch of specific data names at it:


<a id="myLink" href="#"
   data-link-1="http://example.com/first"
   data-link-2="http://example.org/second"
   data-link-3="http://example.net/third">Some examples</a>

Eh.. shrug, yeah, it could work fine. I can certainly come along with some javascript and make a nice floating div with the 3 links. But wait! Where are our labels? Should we just use the addresses for our labels? Could we add data fields for that?

Sure, we could…


<a id="myLink" href="#"
   data-link-1="http://example.com/first"
   data-label-1="the first example"
   data-link-2="http://example.org/second"
   data-label-2="the second example"
   data-link-3="http://example.net/third"
   data-label-3="the third example">Some examples, with labels</a>

What’s the technical term? Oh, yes… Yuk! This looks like it could lead to some cluttered HTML, chock full of data atrributes, and resultant jQuery code that has to constantly do a lot of pattern matching to pick out urls and labels. It could work fine, but I didnt even bother to do my first example with this approach.

Because, after all, we have JSON…

I can assign a block of JSON to a data attribute. jQuery can then come along and parse through that. Groovy.

	<a id="myLinks" class="multilink" href="#"
	data-dls-links='{"allLinks" :[{"label": "one to Techcrunch..", "url": "http://techcrunch.com"},{"label": "and one to pinterest","url": "http://pinterest.com"}]}'>Set of links...</a>

On one hand, it is great that I can refer to one data attribute and find a variable number of labels and urls. On the other, there is a restriction that all of the data must be on the same line.

So much for nice formatting, but let’s work with this for this example, and then improve on it in a second take.

First off, let’s look at the JSON bit, formatted to better express what we’re trying to do:

<!-- just to show structure... -->
data-dls-links='{"allLinks" :[
   {
    "label": "one to Techcrunch..",
    "url": "http://techcrunch.com"
   },
   {
     "label": "and one to pinterest",
     "url": "http://pinterest.com"
   }
]}'>Set of links...

Ok, so “allLinks” is an array of groupings of labels and urls…

There is some usual jQuery code for binding click events, manipulating the css on a div, fading it in and out, etc., but the real key lines are this next batch, where we refer to the data attribute for the current element and build up our list of links:

var myData = $(this).data('dls-links');
var linkHTML = "<ol>";

$.each(myData.allLinks, function(current) {
    linkHTML += '<li><a target="mlwindow" href="' + this.url + '">' + this.label + '</a></li>';
});
linkHTML += "</ol>";

I wanted to be sure to point out that bit, because it will undergo some change in a second pass, in order to make this whole scheme a bit more flexible and not so unwieldy at the HTML element level 1

To be complete, I’ll post the code here, and point to the MultiLink Demo

<!DOCTYPE html>
<head>
	<title>Multilink Demo</title>

<style type="text/css">
body {
	font-family: Arial, "MS Trebuchet", sans-serif;

}
.hideme {
	display: none;
}

.multilink {
	text-decoration: underline;
}
</style>

	<script type='text/javascript' src='http://code.jquery.com/jquery-1.7.1.js'></script>
	<script type='text/javascript'>
$(document).ready(function() {
	$('.multilink').click(function() {

		if ($('#linkdiv').hasClass('hideme')) {
	 		var x = $(this).position().left;
	 		var y = $(this).position().top;

			var cssObj = {
				'z-index'	: 100,
				'display'	: "inline",
				'position'	: "absolute",
				'background' : "wheat",
				'left'		: x,
				'top'		: y,
				'margin-top': "1em",
				'padding'   : "0px 15px 0px 0px",
				'border'	: "double black",

				"-webkit-border-radius" : "10px",
				"-moz-border-radius"	: "10px",
				"border-radius"			: "10px",

			    "-moz-box-shadow" : "rgba(0,0,0,0.5) 10px 5px 24px 4px",
				"-webkit-box-shadow" : "rgba(0,0,0,0.5) 0px 0px 24px",

				'opacity'	: 0
			};

			var myData = $(this).data('dls-links');

			var linkHTML = "<ol>";

			$.each(myData.allLinks, function(current) {
				linkHTML += '<li><a target="mlwindow" href="' + this.url + '">' + this.label + '</a></li>';
			});
			linkHTML += "</ol>";

			$('#linkdiv').html(linkHTML);
			$('#linkdiv').removeClass('hideme');
			$('#linkdiv').css(cssObj);
			$('#linkdiv').stop().animate({opacity: 1.0},300);
		} else {
			$('#linkdiv').stop().animate({opacity: 0},500, function() {
				$('#linkdiv').empty();
				$('#linkdiv').removeAttr("style");
				$('#linkdiv').addClass('hideme');
			});
		}
	});

});
	</script>
</head>

<body>
	<div id="mainContent">
<p>this is my
	<a id="myLinks" class="multilink" href="#"
	data-dls-links='{"allLinks" :[{"label": "one to Techcrunch..", "url": "http://techcrunch.com"},{"label": "and one to pinterest","url": "http://pinterest.com"}]}'>Set of links...</a>
</p>

<p>this is another example
	<a id="myLinks2" class="multilink" href="#"
	data-dls-links='{"allLinks" :[{"label": "appleinsider..", "url": "http://appleinsider.com"},{"label": "facebook","url": "http://facebook.com"},{"label": "flickr..", "url": "http://flickr.com"}]}'>Set of links...</a>
</p>

	</div>

	<div id="linkdiv" class="hideme">I get replaced with the listing of links...</div>
</body>
</html>

As you will see, all of this so far is just setup for what I really want to show, which is:

  • how to use a data attribute as a reference to many IDs within a more centralized chunk of JSON
  • how to give links a tag (think of it much the same way as adding a class to an html element) — building up a list of links will allow you to mix and match absolute IDs and those that match whichever tags you want
  • how to handle optional attributes on a per-link basis

Go to Part 2
Go to Part 3

  1. I’m going to show how to point to data, as opposed to embedding it all
This entry was posted in programming, tech, Technical and tagged , . Bookmark the permalink.