views:

2105

answers:

8

Hello, I'm working on a web application that uses ajax to communicate to the server. My specific situation is the following:

I have a list of users lined out in the html page. On each of these users i can do the following: change their 'status' or 'remove' them from the account.

What's a good practice for storing information in the page about the following:

  • the user id
  • the current status of the user

P.S.: I'm using jQuery.

+5  A: 

Perhaps using custom attributes, so for a user's list element, add attributes for the variables:

<li uid="theuserid" ustatus="thestatus"></li>

The values can then be got with the attr function:

$("li").attr("uid")

And

$("li").attr("ustatus")

Note: The selectors will need to be changed, obviously

Please note that there are differing opinions on the use of custom attributes - however, this should be fine for every major browser. It is also the least complex solution I can think of. It doesn't require jumping to sibling elements to get data, or finding elements nearby, which can all add a small amount of overhead to processing - I try to minimise the amount of extra bloat I add to the DOM when doing such things.

Kazar
Custom attributes work, but are not XHTML compliant
Philippe Leybaert
Yes, but when it comes down to it, which is more desirable - something that works, and is fairly swift, or something that is compliant?
Kazar
@activa and @Kazar Why not have compliant and desirable with the metadata plugin?
antony.trupe
HTML 5 will allow arbitrary attributes that begin with data-. So you could do data-status and be valid HTML 5.
Chuck
+1  A: 

There are various ways of doing it depending on the kind of data you are storing and how much information you are storing in the page in general. It's best to devise a consistent scheme so you can write a simple library call to do the work. For example,

You can store data in the class of a particular element. This may require additional wrapper elements in order to be able to provide an additional class to drive your CSS. This also restricts the storable content format. User ID may well fit into a class attribute.

You can store data in an unused href of a Javascript activated link. This has the additional feature of showing the data in the status bar as part of the URL on rollover. For instance you can store '#userid' or even just 'userid' in the href.

You can store data in additional elements. For instance you can have a nested div with a class that indicates storage which also triggers CSS to take the element out of the display. This is the most general and extensive support you can probably arrange in page.

Rather than a nested div you could also use nested input tags with type="hidden". This is kind of more expected / traditional and doesn't require CSS to take them out of the display. You can use the id attribute to identify these inputs, or you can use the location on the page. For instance, put them inside the link that the user clicks and then just search inside the current link in the onclick handler.

+2  A: 

If you want to store custom data against a jQuery object, use the data function.

If you want to be completely clean and stuff metadata into your html, use hidden fields:

<input type="hidden" name="UserID" value="[userid]" />

You can easily use jQuery selectors to query your list and find html blocks that contain user items that have the relevant hidden fields that match the metadata you are querying for.

Nathan Ridley
+11  A: 

There is jQuery's data function

$('li').data('userid',uid); // sets the value of userid
uid = $('li').data('userid'); // retrieves the value of userid

official documentation: http://docs.jquery.com/Data

Rob
While I agree that the data function is a nice method of storing data in those dom elements, there is still the problem of getting that data to jquery in the first place from the server.
Kazar
That's my concern as well... I still need a way to 'identify' the dom element so I can attach data. Also, I believe I need to keep a separate javascript structure to store all the initial values.
Dan
Ok, I didn't realise the scope of your problem. Take a look at TM's answer.
Rob
Use the metadata plugin for jquery. See my answer for an example(and upvote it!).
antony.trupe
+2  A: 

In this case, I think custom attributes might be overkill. You can store the user-id in the id-attribute, since there will only be one instance of the user in the list, right? Also, the status of the user could be stored in the class-attribute. In this way, each user could be given different styling in CSS, such as green for active, yellow for a non-activated account, and red for a suspended account.

The code for fetching the status will, however, be a little more complex compared to using a custom attribute (But only if you also want to have multiple classes). On a more positive note, the HTML will validate with this approach whereas it would not with custom attributes.

<ul id="userList">
    <li id="uid123" class="active">UserName X</li>
    <li id="uid456" class="suspended">Mr. Troll</li>
</ul>

/**
 * Simple function for searching (strict) for a value in an array
 * @param array arr The array to look in
 * @param mixed val The value to look for in arr. Note that the value is looked for using strict comparison
 * @return boolean true if val is found in arr, else false
 */
function searchArray(arr, val) {
    for(var i = 0, len = arr.length; i < len; i++) {
        if(arr[i] === val) {
            return true;
        }
    }
    return false;
}

/**
 * Gets a known status from a string of class names. Each class name should be separated
 * by a space.
 * @param string classNames The string to check for a known status
 * @return string|false The status if found in classNames, else false
 */
function getStatus(classNames) {
    // The different statuses a user can have. Change this into your own!
    var statuses = ['active', 'suspended', 'inactive'], 
        nameArr = classNames.split(" ");
    for(var i = 0, nameLen = nameArr.length; i < nameLen; i++) {
        // If we find a valid status among the class names, return it
        if(searchArray(statuses, nameArr[i])) {
            return nameArr[i];
        }
    }
    return false; // We didn't find any known status in classNames
}

var id = $("li").attr("id"); // Fetches the id for the first user
var status = getStatus($("li").attr("class")); // Fetches the status of the first user
PatrikAkerstrand
Why was I voted down? The code works, and I've supplied a function for extracting the status from the class-attribute even if other classes are present... IF that is not desired, then just remove the getStatus-function.
PatrikAkerstrand
You can't check the validity of a status on the client-side. You can use CSS to give visual cues about a proper status, since you already use class attributes. But your javascript is basically useless.
Rob
The same could be said about any of the given solutions here. It doesn't matter if the status is stored in a class-attribute or custom attribute. It still have to be validated on the server side. What I meant was that it'll extract a "known" status from a string of class names. I'm not a native english speaker, so I guess it was an unfortunate wording in my post.
PatrikAkerstrand
+1  A: 

To answer the question of "how to get it into the document in the first place", I suggest a layout similar to this:

<ul id="users">
    <li id="someUserId" class="someStatus">Some Username</li>
    <li id="someOtherUserId" class="someOtherStatus">Some Username</li>
</ul>

This allows you to easily select a lot of info about your users:

$('#users > li') // all user elements
$('.someStatus') // all users of a particular status

Then in your event handlers it's also easy to get the current status:

$(this).attr('class') //get current status once you have a user element selected.

Another alternative is to dump javascript to the page and simply have it use the jquery data functionality to store the data as soon as the page loads. You'd still need an id on the element in order to find the right one though.

TM
+2  A: 

The metadata plugin to jquery is your answer.

<html >
<head>
<script src="/js/jquery-1.3.2.js"></script>
<script src="/js/jquery.metadata.js"></script>
</head>
<body>
<ul>
<li type="text" class="{UID:'1',status:'alive'}">Adam</li>
<li type="text" class="{UID:'2',status:'alive'}">Bob</li>
<li type="text" class="{UID:'3',status:'alive'}">Carol</li>
</ul>
<script>
$('li').each(function(){window.console.log($(this).metadata().UID)});
</script>
</body>
</html>
antony.trupe
+5  A: 

There is a lot of debate as to what is best to use. You can store the data a lot of ways, and they all make someone happy - custom attributes will of course not validate if you use XHTML, and using classes to store one or two bits of data is clumsy at best and only gets worse with the amount of things you want to know. Personally, not only am I not a big fan of XHTML, I am also not much of a validation nazi, so I recommend going with the custom attributes.

There is, however, an option that reconciles custom attributes with standards: data- attributes. As John Resig (the author of jQuery) writes about in his blog, this is a new attribute being introduced in HTML5 that allows you to specify custom data attributes with the data- prefix. So a perfectly valid element might look like this:

<ul>
    <li data-userid='5' data-status='active'>Paolo Bergantino</li>
</ul>

This has the upside that while you are still using custom attributes which may be bad if you are using XHTML, your code is going to age very well as this is the way that we will be storing data related to a particular item in the future.

Some further reading is Attributes > Classes: Custom DOM Attributes for Fun and Profit.

Paolo Bergantino