Skip to content

Instantly share code, notes, and snippets.

@jamesarosen
Created April 1, 2011 19:26
Show Gist options
  • Save jamesarosen/898696 to your computer and use it in GitHub Desktop.
Save jamesarosen/898696 to your computer and use it in GitHub Desktop.

Let's say you have a <table> of Cats, each of which has a link to a "more info" page:

NameBornAdopted?
Claudius17 FebYes
Willow29 FebNo
Sawtooth Sparrow-Eater08 MarNo
<!-- source: -->
<table class='cats'>
  <thead>
    <tr><th>Name</th><th>Born</th><th>Adopted?</th></tr>
  </thead>
  <tbody>
    <tr><td><a href='#/cats/14-claudius'>Claudius</a></td><td><time datetime="2011-02-17">17 Feb</td><td>Yes</td></tr>
    <tr><td><a href='#/cats/15-willow'>Willow</a></td><td><time datetime="2011-02-29">29 Feb</td><td>No</td></tr>
    <tr><td><a href='#/cats/16-Sawtooth-Sparrow-Eater'>Sawtooth Sparrow-Eater</a></td><td><time datetime="2011-03-08">08 Mar</td><td>No</td></tr>
  </tbody>
</table>

Your product team says, "we'd really like it if the user could click anywhere on the row to go to the 'more info' page." Your first thought is to move the <a> tags outside the <tr>s:

NameBornAdopted?
Claudius17 FebYes
Willow29 FebNo
Sawtooth Sparrow-Eater08 MarNo
<!-- source: -->
<table class='cats'>
  <thead>
    <tr><th>Name</th><th>Born</th><th>Adopted?</th></tr>
  </thead>
  <tbody>
    <a href='#/cats/14-claudius'><tr><td>Claudius</td><td><time datetime="2011-02-17">17 Feb</td><td>Yes</td></tr></a>
    <a href='#/cats/15-willow'><tr><td>Willow</td><td><time datetime="2011-02-29">29 Feb</td><td>No</td></tr></a>
    <a href='#/cats/16-Sawtooth-Sparrow-Eater'><tr><td>Sawtooth Sparrow-Eater</td><td><time datetime="2011-03-08">08 Mar</td><td>No</td></tr></a>
  </tbody>
</table>

Sadly, that's not valid HTML. Even more sadly, browsers aren't too happy with this markup.

"I know," you say, "let's solve the problem with some spiffy Javascript." You return to the original markup and add some jQuery:

$('table.cats tr').each(function() {
  var href = $('td:first-child a', this).attr('href');
  $(this).click(function() { window.location.href = href; });
});

Ruxpin, Your UX-professional alter-ego also reminds you to make the whole <tr> feel like a link since it's clickable:

table.cats tr { pointer: cursor; }

This solves the problem, but it introduces a new one: users who command-click (or control-click on Windows) will get both the browser default behavior (opening the "more info" page in a new tab) and your custom behavior (opening the "more info" page in the current tab). This is... less than optimal.

One solution to the double-open problem is to prevent the default behavior on the <a>:

$('table.cats tr td:first-child a').click(function(event) {
  event.preventDefault();
  event.stopPropagation();
});

But this is a cut-off-the-PBR-to-spite-the-hipster problem since this now stops the user from ever using command-click on the link to open the "more info" page in a new tab.

I haven't been able to think of any semantically-correct solutions that work across browsers.

I tried the following:

$('table.cats tr').click(function(event) {
  $('td:first-child a', this).trigger(event);
});

but triggering a click event doesn't actually cause the browser to follow the link; it only triggers any registered click handlers.

The best I've come up with that actually works is

$('table.cats tbody tr').each(function() {
  var myInfoLink = $('td:first-child a', this)[0];
  if (!myInfoLink) { return; }
  $(this).click(function(event) {
    if (!event) { return; }
    // don't override link-click behavior:
    if (event.target === myInfoLink) { return; }
    event.preventDefault();
    event.stopPropagation();
    if (event.ctrlKey || event.metaKey) {
      window.open(myInfoLink.href, '_blank');
    } else {
      window.location.href = myInfoLink.href;
    }
  });
});

I'd love to hear any suggestions.

@jish
Copy link

jish commented Apr 1, 2011

Ruxpin, Your UX-professional alter-ego...

huh? :P

@jamesarosen
Copy link
Author

Nope, that won't work. The trigger('click', event) will then bubble back to the <tr>, recursing endlessly.

@jish
Copy link

jish commented Apr 1, 2011

Your last suggestion:

$('table.cats tr').click(function(event) {
  $('td:first-child a', this).trigger('click', event);
});

...looks like the best one. Does it work across all browsers?

@jamesarosen
Copy link
Author

Additionally, $(some link).click() doesn't actually simulate a user clicking the link. We'll need to use the full document.location.href= or window.open, depending on the event's metaKey attribute.

@jamesarosen
Copy link
Author

AFAICT, there is no way to open a URL in a new tab or window, allowing the browser to specify which. The only option is this tab (document.location.href=) or a new window (window.open).

@moopet
Copy link

moopet commented Apr 2, 2011

Another approach is to duplicate the anchor across all TDs in the row and set them to be block elements. Not saying it's ideal, but it will take care of the cmd-click issues you're talking about:

<style>
td a {
    display: block;
    width: 100%;
    height: 100%;
}
</style>
<script type="text/javascript">
$('td a').each(function() {
    var $a = $(this);
    var href = $a.attr('href');
    $('td', $a.closest('tr')).each(function() {
        var $td = $(this);
        if (!$('a', $td).length) {
            $td.html('<a href="' + href + '">' + $td.html() + '</a>');
        }
    });
});
</script>

@wjcrowcroft
Copy link

My suggestion in this case - sadly - would be to markup the table in anchor tags, eg.<a class="tr"> and try using .tr { display:table-row }

Not perfect, semantically sucks balls, and not really supported cross-browser (can't remember the exact stats), but could use fallbacks for IE0.1+, if it pleases the client/sales team?

@jish
Copy link

jish commented Apr 3, 2011

Added another idea here: https://gist.github.com/900620

The downside is that you can not command click on other parts of the row, just the link.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment