DOM-based data storage and retrieval using jQuery

The popular, and free (MIT and GPL-licensed), jQuery JavaScript library has a concise and portable set of JavaScript APIs for rapid web development. In this article, learn how the jQuery data() method can simplify the task of associating data to DOM elements. In-depth examples show how to use the method in your own applications. Discover how jQuery lets you use HTML5 data-* attributes in your jQuery-powered applications.

C. Enrique Ortiz, Developer and author, About Mobility Weblog

C. Enrique Ortiz is a long-time mobile technologist, developer and author. He blogs at the About Mobility weblog and is the founder of the Austin chapter of MobileMonday.



22 February 2011

Also available in Chinese Japanese

Introduction

The jQuery library is lightweight (around 25KB when minified/Gzipped), CSS3 compliant, and cross-browser. It provides a rich API set including HTML document object model (DOM) traversing and manipulation, working with events, and provides server communication using Asynchronous JavaScript and XML (Ajax) requests APIs. In addition it provides animation and image effects for webpages, and a powerufl plug-in architecture.

In this article, learn how to use data storage facilities in jQuery to embed custom non-visible data in a web page by associating data with a specific DOM-element. Learn how to use it in your own applications, with some in-depth examples, and see how jQuery allows you to use HTML5 data-* attributes in your jQuery-powered applications.

To follow along with this article, you will need:

  • Previous exposure to HTML
  • An understanding of JavaScript fundamentals
  • A basic knowledge of jQuery

You can download the source code and examples used in this article.

Attaching data to DOM elements

Sometimes there's a need to store hidden information or metadata associated with particular elements of your web page. Having this information available without having to retrieve it separately simplifies your page and associated code. The hidden information can be used in many ways, such as for styling purposes, for calculations as the user selects a specific UI element, and for filtering the results to be displayed to the user.

Typically, including hidden information within the web page required creative approaches. For example:

  • Storing information within HTML element attributes such as id, class, rel, and title, thus overriding the attributes' original intent.
  • Using <span> or <div> blocks that contain the information, while making such blocks invisible to the user through styling (style="display: none;").
  • Adding JavaScript code to the web page to define data structures that map to HTML ID elements.
  • Adding your own attributes to existing HTML elements (breaking the HTML standard itself, and relying on the HTML browser to ignore any syntax errors).

Different approaches are only limited by the creativity of the developer.

The approaches above are not elegant and are not good coding practice. But, there's good news—jQuery has a facility that simplifies associating data to DOM elements in a clean, cross-browser manner.


The jQuery data() method

With the jQuery data() API you can store and retrieve data associated with specific DOM elements. This is an exceptionally powerful feature with support for various data types, including JavaScript objects. The jQuery data() method allows for true separation of your HTML views from your data by keeping data hidden while associated with specific DOM elements. This approach helps to keep the HTML itself clean, and avoids Ajax calls to retrieve the additional static information that you need.

The jQuery JavaScript library defines two data methods, as shown in Table 1.

Table 1. jQuery data methods
General formDescriptionFormat
jQuery.data (or $.data)Store arbitrary data associated with the specified element.jQuery.data(element, key, value)jQuery.data(element, key)jQuery.data(element)
jQuery.fn.data (or $.fn.data)Store arbitrary data associated with the matched elements..data(key, value).data(obj).data(key).data()

With jQuery.data(), data is associated with a specific DOM element. This form is not as practical as jQuery.fn.data(), as it requires you to select and keep track of the element of interest. While this form of data() is much faster than the other, it is intended for low-level use by the jQuery framework.

With jQuery.fn.data(), data is associated with DOM elements that match the specified jQuery selection criteria. It's a more practical form of the method because jQuery performs for you the selection of the elements based upon the passed selection criteria. $.fn.data executes an element selector and is slower than $.data

Starting with jQuery 1.4.3, $fn.data() will return HTML5 data attributes from the HTML DOM. HTML5 data storage and jQuery have more details on this.

The rest of this article focuses mainly on jQuery.fn.data().


DOM-based data storage and retrieval in jQuery

First, some basics. When a web page (or XML document) is loaded by the browser, it is parsed and a DOM representation of it is created. Listing 1 shows an example of a simple HTML file.

Listing 1. Simple HTML file
<table>
    <tbody>
        <tr>
            <td>Shady Grove</td>
            <td>Aeolian</td>
        </tr>
        <tr>
            <td>Over the River, Charlie</td>
            <td>Dorian</td> 
        </tr>
    </tbody>
</table>

Figure 1 shows the associated DOM, recreated from the original W3C specification document (see Resources for a link).

Figure 1. DOM graphical representation of HTML in Listing 1
A DOM graphical representation of the HTML in Listing 1.

With DOM, anything found in the HTML or XML document (elements and content) can be programmatically accessed, added, deleted, or changed.

With jQuery, you can associate JavaScript data types (strings, numbers, objects, arrays, events, and functions) with a particular DOM element. The data is stored in an internal indexed jQuery cache JavaScript object. The association between named data and the DOM element is what makes DOM-based data storage and retrieval possible in jQuery. Listing 2 shows the definition of the cache and the jQuery.data() method.

Listing 2. Definition of jQuery.cache and low-level jQuery.data() method
(function( jQuery ) {

jQuery.extend({

cache: {},

// Please use with caution
uuid: 0,

// Unique for each copy of jQuery on the page   
expando: "jQuery" + jQuery.now(),

:
:

data: function( elem, name, data ) {
    if ( !jQuery.acceptData( elem ) ) {
        return;
    }

    elem = elem == window ?
        windowData :
        elem;

    var isNode = elem.nodeType,
        id = isNode ? elem[ jQuery.expando ] : null,
        cache = jQuery.cache, thisCache;

    if ( isNode && !id && typeof name === "string" 
&& data === undefined ) {
        return;
    }

    // Get the data from the object directly
    if ( !isNode ) {
        cache = elem;

    // Compute a unique ID for the element
    } else if ( !id ) {
        elem[ jQuery.expando ] = id = ++jQuery.uuid;
    }

    // Avoid generating a new cache unless none exists and we
    // want to manipulate it.
    if ( typeof name === "object" ) {
        if ( isNode ) {
            cache[ id ] = jQuery.extend(cache[ id ], name);

        } else {
            jQuery.extend( cache, name );
        }

    } else if ( isNode && !cache[ id ] ) {
        cache[ id ] = {};
    }

    thisCache = isNode ? cache[ id ] : cache;

    // Prevent overriding the named cache with undefined values
    if ( data !== undefined ) {
        thisCache[ name ] = data;
    }

    return typeof name === "string" ? thisCache[ name ] : thisCache;
},

:
:

The jQuery.fn.data() method is defined similarly. As a separate exercise you can explore its definition, using data.js at Github for assistance (see Resources for a link).

In the following sections, learn how to store and retrieve the data stored in the indexed jQuery data cache, which is associated with a given DOM element.


Storing and retrieving data

As mentioned, with jQuery you can perform DOM-based data storage and retrieval of any JavaScript data types, including strings, numbers, objects, arrays, events, and functions. The data is stored in an internal indexed jQuery cache JavaScript object.

To show how to store and retrieve data using the jQuery data method, the following example involves a web page that uses a CSS-based table and a filter function to filter rows based on the data associated with the particular row DOM element. Figure 2 shows a sample.

Figure 2. DOM-based data storage and retrieval, sample web page
A table with a filter section on the left and four columns of different filter criteria.

The content in the sample is a table showing the restaurant name, the type of food served, the location, and the restaurant's rating. The body of the web page consists of several <div> sections that define a sidebar and the table or grid itself, as shown in Listing 3.

Listing 3. HTML content
<body>
    <div id="sidebar">
        Filter by type, location or rating:
        <input type="text" />
        <button id="filter">Filter</button>
        <button id="clear">Clear</button>
        <p>
        To keep the sample code simple, the search terms are "ORed". Example 
"seafood 2 stars downtown" which returns all rows that match seafood OR 2+ stars 
OR in downtown.
        </p>
    </div>

    <div id="rows">
        <p>
        This sample web page shows how to use the <code>jQuery.data()</code> 
method. It uses a CSS-based table and a filter function that filters rows based on the 
data associated with the particular row DOM-element.
        </p>

        <div class="row" id="row1">
            <div class="cell"><b>Restaurant</b></div>
            <div class="cell"><b>Type of Food</b></div>
            <div class="cell"><b>Location</b></div>
            <div class="cell"><b>Rating</b></div>
        </div>

        <div class="row" id="row2">
            <div class="cell">Manuel's</div>
            <div class="cell">Mexican</div>
            <div class="cell">Arboretum Area, Downtown</div>
            <div class="cell">3 Stars</div>
        </div>

        <div class="row" id="row3">
            <div class="cell">NoRTH</div>
            <div class="cell">Italian</div>
            <div class="cell">North Austin</div>
            <div class="cell">4 Stars</div>
        </div>

        <div class="row" id="row4">
            <div class="cell">Perlas Seafood</div>
            <div class="cell">Seafood</div>
            <div class="cell">Downtown</div>
            <div class="cell">5 Stars</div>
        </div>

        <div class="row" id="row5">
            <div class="cell">Rudys</div>
            <div class="cell">BBQ</div>
            <div class="cell">North Austin, Downtown, South Austin, Round Rock, 
Dallas</div>
            <div class="cell">3 Stars</div>
        </div>

        <div class="row" id="row6">
            <div class="cell">Chuys</div>
            <div class="cell">Tex Mex</div>
            <div class="cell">North Austin, Downtown, South Austin</div>
            <div class="cell">2 Star</div>
        </div>

        <div class="row" id="row7" data-id="7" data-type="Sushi" data-stars="3" 
data-area="downtown">
            <div class="cell">Midoro</div>
            <div class="cell">Sushi</div>
            <div class="cell">Downtown</div>
            <div class="cell">4 Star</div>
        </div>

    </div>
</body>

Each row is a class row and has a unique ID that's used to identify the DOM element and to associate the data with it. Listing 4 shows an example.

Listing 4. Table row in CSS and unique ID
<div class="row" id="row6">
            <div class="cell">Chuys</div>
            <div class="cell">Tex Mex</div>
            <div class="cell">North Austin, Downtown, South Austin</div>
            <div class="cell">2 Star</div>
</div>

Listing 4 is the static part of the sample web page. The rest of the web page is the JavaScript that uses jQuery to store the data associated with a particular DOM element, retrieves the data, and dynamically filters the information based on filtering criteria.


Using JavaScript and jQuery

In the JavaScript, the first task is to add the click handlers inside the ready() event handler, as shown in Listing 5.

Listing 5. ready() event handler
<script type="text/javascript">

    /* Ready */
    $(document).ready(function() {
        $('#filter').click(function () {
            filterRows($('input').val());
        });
        $('#clear').click(function () {
            $('input').val('')
            clearRows($('input').val());
        });
    });
:
:

The code adds the click handlers for the filter and clear buttons. The filter button triggers the table view content filtering, while the clear button resets the table back to its original view state.

The next step, following the example illustrated in Figure 2, is for the jQuery code to associate the hidden metadata to specific DOM elements. For this, you need to associate a JavaScript object that holds the metadata; in this example, attributes for IDs, type, stars, and an area, to each of the table rows. Listing 6 shows an example of how to use a jQuery selector to select a particular DOM element and calling .data() for the selected element to add the JavaScript object to the DOM element. As with JavaScript objects, other member data types can be integers, strings, and more complex types, such as arrays, functions, and other objects.

Listing 6. Associating data to specific DOM elements (jQuery)
:
:
    /* Associate data to specific DOM-elements */
    $('#row1').data({ id:1, type:'rowheader'});
    $('#row2').data({ id:2, type:'mexican', stars:3, area:'north'});
    $('#row3').data({ id:3, type:'italian', stars:4, area:'north'});
    $('#row4').data({ id:4, type:'seafood', stars:5, area:'downtown'});
    $('#row5').data({ id:5, type:'bbq',     stars:3, area:'west'});
    $('#row6').data({ id:6, type:'tex mex', stars:2, area:'south'});
:
:

Listing 7 shows the implementation for the click handlers added to the $(document).ready() function described in Listing 5. The function clearRows() is used to reset the table view to its original state, and filterRows() to filter the table view based on the filtering criteria compared to the stored DOM data.

Listing 7. Click handlers
:
:
    /* Clear Rows */
    function clearRows(filterString) {
        // For each row, that is, div in #rows of class .row
        $.each($('#rows .row'), function(i, row) {
            $(row).show();
        });
    }

    /* Filter Rows */
    function filterRows(filterString) {

        // For each row, that is, div in #rows of class .row
        $.each($('#rows .row'), function(i, row) {
            var $row = $(row); // Get the row div element
            var rowData = $row.data(); // Get the data associated with the row 
div element
            var id = rowData.id; // Get the row id
            var type = rowData.type;
            if (filterString.length == 0) {
                $row.show();
            } else {
                if (type.toLowerCase().search("rowheader") != -1) {
                    $row.show();
                } else {
                    if (filterByType(filterString, rowData.type) ||
                        filterByRating(filterString, rowData.stars) ||
                        filterByLocation(filterString, rowData.area)) {
                        $row.show();
                    } else {
                        $row.hide();
                    }
                }
            }
        });
    }
:
:

Let's take a closer look at how the code executes a jQuery selector for each of the table rows: $.each($('#rows .row') and function(i, row). For each selected row, extract the row element and its associated data, as shown in Listing 8.

Listing 8. Retrieving DOM element data
var $row = $(row); // Get the row div element
var rowData = $row.data(); // Get the data associated with the row div element

The rest of the functions perform the actual filtering based on type, rating (or stars), and area/location. Listing 9 shows an example.

Listing 9. Filtering content based on the DOM element data
:
:
    /* Filter Rows by Type */
    function filterByType(filterString, type) {
        var p1 = RegExp(type);
        if (p1.test(filterString)) {
            return true;
        } else {
            return false;
        }
    }

    /* Filter Rows by Rating */
    function filterByRating(filterString, stars) {
        if (filterString.toLowerCase().search('star') != -1) {
            var value = filterString.replace(/[^0-9]/g,'');
            if (stars >= value) {
                return true;
            } else {
                return false;
            }
        }
    }

    /* Filter Rows by Location */
    function filterByLocation(filterString, area) {
        var p1 = RegExp(area);
        if (p1.test(filterString)) {
            return true;
        } else {
            return false;
        }
    }

</script>

You can change or improve the code in Listing 9 by adding other filtering logic and functions.

You can download the dom-based-data-sample.html file to get all of the above HTML content, associated JavaScript, and jQuery code for your own use.


HTML5 data storage and jQuery

HTML5 introduces new custom data attributes for embedding custom, non-visible data in a web page. As the W3C defines, "these new custom data attributes are intended to store custom data private to the page or application, for which there are no more appropriate attributes or elements."

From the perspective of jQuery, the new HTML5 custom data attributes target the same issue addressed by the jQuery data() methods. The HTML5 data attributes are limited to string data. With jQuery data() you can store any kind of JavaScript data types, from ints and strings to arrays, functions, and other objects.

Starting with jQuery 1.4.3, .data() automatically extracts, stores (in the cache), and returns HTML5 data attributes from the HTML DOM.

HTML5 data attributes are defined as data-* attributes, where data- is the required prefix name of the attribute, and * can be any sequence of characters as defined by the W3C. A custom data attribute is an attribute in no namespace whose name starts with the string "data-", has at least one character after the hyphen, is XML compatible, and contains no characters in the range U+0041 to U+005A (LATIN CAPITAL LETTER A to LATIN CAPITAL LETTER Z).

The HTML code snippet in Listing 10 contains a row definition that adds the same metadata added above using the .data() APU, but this time using HTML5 custom attributes.

Listing 10. DOM-based data using HTML5
<div class="row" id="row7" 
    data-id="7" 
    data-type="Sushi" 
    data-stars="3" 
    data-area="downtown">
    <div class="cell">Midoro</div>
    <div class="cell">Sushi</div>
    <div class="cell">Downtown</div>
    <div class="cell">4 Star</div>
</div>

The beauty of this solution is that you do not have to change the code to support HTML5. jQuery data() automatically detected the customer data attributes, parsed them, loaded them into the cache, and returned them when requested.


Conclusion

In this article, you learned about the jQuery data() methods, with a focus on jQuery.fn.data(). These jQuery data storage facilities let you embed custom, non-visible data in a web page by associating data with a specific DOM element, thus providing for DOM-based data storage and retrieval. You can now store any type of JavaScript data in a clean manner.


Download

DescriptionNameSize
Article source codedom.based.data.sample.zip3KB

Resources

Learn

Get products and technologies

  • jQuery: Download the jQuery JavaScript library, available under either the MIT or GNU Public License. You can either download it and serve it locally or include and serve it directly from the Google CDN.
  • Innovate your next development project with IBM trial software.

Discuss

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Web development on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Web development
ArticleID=628200
ArticleTitle=DOM-based data storage and retrieval using jQuery
publish-date=02222011