views:

94

answers:

5

I'm usually a C# developer, but writing a mostly-client side application using jQuery.

It is reasonably straight forward: I have a list of "groups" which have some parameters (like a group name) and a list of "users" who also have some parameters.

At the moment I try to manage that using a <li> with a specific id, so there is a lot of string-matching involved to turn <li id="group-2">Name - ExtraInfo</li> back into something I can work with.

I feel that this approach is stupid because a) I use the UI as back-end for state and b) I rely on string parsing rather than working with real objects.

In C# I would just create a DTO (essentially a List<Group>), but I have not enough experience in JavaScript/jQuery to do that there.

Can someone give me some quick tips how to create a custom object and manage a list of these?

+4  A: 

I'd just use arrays and objects (let's say JSON):

var groups = [
    {
        name: "Name",
        info: "Extra"
    },
    {
        name: "Name",
        info: "Extra"
    }
];

Regarding manipulation of the array. jQuery has some array utilities. For the question in your comment, you'd use grep:

var filteredGroups = groups.grep(function (group, i) {
    return group.name == "What I'm interested in";
});

It's the equivalent of a Select().Where() in Linq (I'm not a .NET expert so there may be some things that don't match).

Anyway, that would be just the model part of an MVC structure. You still need some functions to map a collection of groups to a <ul> element. Then you'd have the view too.

Ionuț G. Stan
Thanks. Can I easily modify this array? (Remove from Array where Name equals "Something")? I think the UI Manipulation should be straight forward using jQuery (find the <ul>, delete all <li>, loop through the array and create each element as <li>)
Michael Stum
Yes, there is the `delete` operator that does just that: Find out the array index that holds the object with name "Something", and issue `delete groups[i]` (but note that other array members will keep their index!)
Tomalak
P.S.: Maybe using nested objects instead of an array of objects is more intuitive here. You'd also get the ability to look-up child objects by their ID directly, without the need to to `grep()`.
Tomalak
+1  A: 

You should not care about the string matching this is wrapped by jQuery for good reasons!

The fastest way without jQuery would be

document.getElementById('idOfLiElement');
powtac
Yes, but at the moment i am "encoding" my parameters into a string. my HTML looks like <li id="group-2">Name - ExtraInfo</li> which encodes 3 Parameters: An ID (2) a name (Name) and some extra info (ExtraInfo). If I want to read this, I need to parse the fields out of it. I want to move away from that approach to a real Object-Oriented approach, but I don't know how yet.
Michael Stum
Ok I see, then use JSON as your "Frontend Object Notation" as Ionut G. Stan shows in his answer http://stackoverflow.com/questions/1537348/javascript-jquery-dtos-objects-to-hold-state/1537361#1537361.
powtac
+2  A: 

You could use a structure like the following. You would want to flesh it out with more detail, and group probably has a similar structure for an internal array of users.Also some error handling for impossible values (like id = -201) wouldn't hurt.

function Group(id, name, info)
{
    var _id = id;
    var _name = name;
    var _info = info

    this.getID = function()
    {
        return _id;
    }

    this.getName = function()
    {
        return _name;
    }

    this.getInfo = function()
    {
        return _info;
    }
}

function GroupList()
{
    var _groups = [];

    this.addGroup = function(group)
    {
        _groups.push(group);
    }

    this.getGroup = function(id)
    {
        var group;
        for(var index = 0, length = _groups.length; index < length; ++index)
        {
            group = _groups[index];
            if (id === group.getID())
            {
                return group;
            }
        }
    }
}

If you're going for a OOP style as above, I'd recommend Prototype as it makes class inheritance easier. Then it's just a matter of writing a generic List and extending from that (see http://api.prototypejs.org/language/class.html). Prototype also provides, amongst other things, a pretty broad set of functions for working with arrays and enumerables (see http://api.prototypejs.org/language/enumerable.html).

Jonathan Fingland
+1  A: 

Expanding on Ionut G. Stan's answer, I suggest nested objects:

var groups = {
  group1: {
    name: "Group 1",
    users: {
      uid1: { name: "User 1" },
      uid2: { name: "User 2" },
      uid3: { name: "User 3" }
    }
  },
  group2: {
    name: "Group 2",
    users: {
      uid1: { name: "User 1" },
      uid4: { name: "User 4" }
    }
  }
};
  • Check:
    if ("group1" in groups && "uid1" in groups["group1"].users) /* ... */;
  • Fetch:
    var username = groups["group1"].users["uid1"].name
  • Remove:
    delete groups["group1"].users["uid1"];
  • Add:
    groups["group1"].users["uid4"] = { name: "User 4" };

To avoid unnecessary duplication and insert paradoxons:

// all relevant users, for look-up purposes
var allUsers = {
  uid1: { name: "User 1" },
  uid2: { name: "User 2" },
  uid3: { name: "User 3" },
  uid4: { name: "User 4" }
}

// groups reference the ID only, details are in allUsers["uid1"] etc
var groups = {
  group1: {
    name: "Group 1",
    users: {uid1: 1, uid2: 1, uid3: 1}
  },
  group2: {
    name: "Group 2",
    users: {uid1: 1, uid4: 1 }
  }
};
  • Check:
    if ("group1" in groups && "uid1" in groups["group1"].users) /* ... */;
  • Fetch:
    var username = allUsers["uid1"].name
  • Remove:
    delete groups["group1"].users["uid1"];
  • Add:
    groups["group1"].users["uid4"] = 1;
Tomalak
Looks like C#'s anonymous types, interesting. Can I have functions as well? i.e. group1: { name: "Group 1", Dialog: function() { alert(name); }
Michael Stum
Of course. In JavaScript everything is an object, so functions are an object, too. ;-)
Tomalak
+1  A: 

You can also use jQuery's data function to store groups for easy retrieval.

var group1 = {
 name: "Group 1",
 users: {
  uid1: { name: "User 1" },
  uid2: { name: "User 2" },
  uid3: { name: "User 3" }
 }
}

$('#ArbitraryElementID').data('Group 1', group1);

then you can use:

var group1 = $('#ArbitraryElementID').data('Group 1');

to retrieve the object.

JoshNaro