2009-05-31

Simple loading of HTML fragment using jQuery AJAX

jQuery provides a simple load() function to load an HTML fragment using AJAX. To test it, create a test data file called data.html:

<html>
  <body>
    <ul>
      <li>Item 1</li>
      <li>Item 2</li>
      <li>Item 3</li>
      <li>Item 4</li>
    </ul>
  </body>
</html>

Next, create a target HTML file called testLoad.html in the same folder with the following jQuery statement:

<html>
  <head>
    <title>jQuery load HTML test</title>
    <script type='text/javascript' src='js/jquery-1.3.2.min.js'></script>
    <script type="text/javascript">
      $(document).ready(function() {
        $('#myLinks').load('data.html ul li');
      });
    </script>
  </head>
  <body>
    <ul id="myLinks"></ul>
  </body>
</html>

When you view testLoad.html, you should see the list items in data.html inserted into the target file, in the unordered list named myLinks.

It was a little fiddly to get this working the first time. If your source HTML file has an error, nothing seems to happen; in that case, check your browser's error console to see what went wrong. For instance, in Firefox, when my source HTML file wasn't well-formed, I found this error:

Error: mismatched tag. Expected: </ul>.
Source File: 
Line: 8, Column: 5
Source Code:
  </body>

Another thing I found is that you can't include an XML processing instruction (<? ... ?> lines) in your data file because when load() tries to insert your XML file into your target document, you would get an error like this:

Error: XML or text declaration not at start of entity
Source File: 
Line: 1, Column: 43
Source Code:
<div xmlns="http://www.w3.org/1999/xhtml"><?xml version="1.0" encoding="UTF-8"?>

2009-05-29

Selecting parent or ancestor of a node in jQuery

When manipulating an HTML document (especially one that you didn't generate), it can be easier to find a node by matching its descendant's unique id or class attribute and value first, then selecting that descendant's ancestor (which is the node you wanted to in the first place), compared to finding that node by referring to its position in the DOM, which is not obvious and isn't easy to maintain.

For example, in the Australian Government Bureau of Meterology site, you might want to highlight temperature and forecast for Melbourne, so the simplest thing to do is change the style of the row containing that string, but there's no unique attribute you can use to select that row (or tr node):

<tr>
…
</tr>
<tr>
  <td>
    <div>
      <table>
        <tbody>
          <tr>
            <td><a href='…'>Sydney</a></td>
            <td>20</td>
            <td>Shower or two</td>
          </tr>
          <tr>
            <td><a href='…'>Melbourne</a></td>
            <td>16</td>
            <td>Shower or two</td>
          </tr>
          …
        </tbody>
      </table>
      <table>
      …
      </table>
    </div>
  </td>
</tr>

For this site, the trick is to select the td node containing Melbourne, then find the first tr ancestor. Here's a sample script using jQuery:

// ==UserScript==
// @name           www.bom.gov.au Highlight City
// @namespace      kamhungsoh.com
// @description    Highlight row of a specific city.
// @require        http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js
// @include        http://www.bom.gov.au
// ==/UserScript==

$("a:contains(Melbourne)").each(function() {
  $(this).parents('tr:eq(0)').css('background-color', 'grey');
});

In this script, for each a node with a value of Melbourne, find the first tr parent using :eq(0) and change its background colour. You have to constrain the selection of parents to the first parent, otherwise all the tr ancestors will be selected; on this site, nested tables are used for layout so without this constraint, the enclosing tr node of the table will also be found and modified.

2009-05-27

Zebra-stripe table rows with jQuery's custom selectors

I thought I had a simple way to zebra-stripe table rows in jQuery:

$('table tbody tr').each(function(i) {
  $(this).addClass(i%2 ? 'OddRow' : 'EvenRow');
});

While I was looking up jQuery selectors, I found that the library has two custom selectors, :odd and :even, to select the odd and even elements in a matched element set, respectively, so you could zebra-stripe a table like this:

$('table tbody tr:odd').addClass('OddRow');
$('table tbody tr:even').addClass('EvenRow');

The second example seems a little more obvious.

See Also

2009-05-26

Read 'The Economist' article comments earliest first

A simple GreaseMonkey script using jQuery to show the comments to articles in The Economist, from earliest first. Basically, this script looks for <a> tags with specific text in their href attribute and appends &sort=asc. It's shorter and easier to read than the original plain Javascript version.

See Also