Good jQuery Question


var listItems = "";

$.each(msg.d, function(index, value) {
    listItems += "<li><a href='#' class='" + value.Availability + "' title='" + value.Time + "' >" + value.Time + " - " + value.Availability + "</a></li>"
    
});

var teeTimeLinks = $(listItems + 'li');

$.each(teeTimeLinks, function() {
    var link = $(this).find('a');

    link.bind('click', function(event) {
        event.preventDefault(); //stop the link from going to href
        TeeTimeSelected(this);
    });
});


The above code works. BUT, msg.d returns 80 objects. We then loop through it and make our list items. AND then we loop through it again and apply the click event. How can this be optimized into one loop?

Any thoughts? pmw57? Raffles? Gotta be a way to get it done in one loop instead of two?

Perhaps if we knew more clearly where msg.d comes from and in what format, and how teeTimeLinks will be used after this, we could come up with some alternative code inbetween.

msg.d is the returned JSON. About 80 objects with the properties of Availability and Time is all. The code works, but I can’t help but think there’s gotta be more efficient way to do it. Somehow attach the event handler as I create the listItem…


function ReturnTeeTimesForThisDate(msg) {
    var totalTeeTimes = msg.d.length;
    var listItems = "";

    if (totalTeeTimes != 0) {

        $.each(msg.d, function(index, value) {
            listItems += "<li><a href='#' class='" + value.Availability + "' title='" + value.Time + "' >" + value.Time + " - " + value.Availability + "</a></li>"

        });

        //Returns a list of tee times and applies CSS and event handlers
        var teeTimeLinks = $(listItems + 'li');

        $.each(teeTimeLinks, function() {
            var link = $(this).find('a');

            link.bind('click', function(event) {
                event.preventDefault(); //stop the link from going to href
                TeeTimeSelected(this);
            });
        });

        $('#teeTimeList').html(teeTimeLinks);
    }
}


I don’t understand this line:

var teeTimeLinks = $(listItems + 'li');

Surely teeTimeLinks is just going to be a string, with a seemingly random ‘li’ at the end:

'<li><a>...</a></li><li><a>...</a></li><li><a>...</a></li>li

In any case, you need to do something like this:

var a;
$.each(msg.d, function(index, value) {
  a = $('<a href="#" class="' + value.Availability + '" title="' + value.Time + '">' + value.Time + ' - ' + value.Availability + '</a>');
  a.click(function(event) {
    event.preventDefault(); //stop the link from going to href
    TeeTimeSelected(this);
  });
  $('<li></li>').append(a).appendTo($('#some_list'));
});

By the way, you really need to stop the habit of using single quotes for HTML attributes. Use double quotes.

Here’s some working code that does the job. The $teeTimeList variable indicates that it’s a jQuery object, instead of a normal object.


function ReturnTeeTimesForThisDate(msg) {
    var totalTeeTimes = msg.d.length;
    var $teeTimeList = $('<ul>');
 
    if (totalTeeTimes != 0) {
        $.each(msg.d, function(index, value) {
            $teeTimeList.append(
                $('<li>').append(
                    $('<a href="#" class="' + value.Availability + '" title="' + value.Time + '" >' + value.Time + ' - ' + value.Availability + '</a>')
                    .bind('click', function(event) {
                        event.preventDefault(); //stop the link from going to href
                        TeeTimeSelected(this);
                    })
                )
            );
        });

        $('#teeTimeList').html($teeTimeList);
    }
}

Raffles - Hope you are doing well.

var teeTimeLinks = $(listItems + ‘li’);there was supposed to be a space before the li so ’ li’ that way it would be a selector. As in find all li in listItems…

The thing I don’t like about your solution is the appendTo($(‘#some_list’));
Doesn’t that make me traverse the DOM every time?

>>By the way, you really need to stop the habit of using single quotes for HTML attributes. Use double quotes.

Really? That’s a problem?

It was for me. When I was editing the code I always had to backtrack, scanning up and down the code to check what context the quote was supposed to be. Is it a JavaScript quote or is it supposed to be an HTML quote. You’ll find that the code I provided for you above has the quotes now in the standard fashion.

By sticking to the standard of doublequotes for HTML attribute quotes and single quotes for JavaScript strings, we can then instantly know what the content is supposed to be.

Paul, good solution. I’ll have to work with it as ‘#teeTimeList’ is already a UL; so I’m adding a UL to a UL.

By sticking to the standard of doublequotes for HTML attribute quotes and single quotes for JavaScript strings, we can then instantly know what the content is supposed to be.

That’s a good call. Thanks for your help guys.

You should be able to get rid of the <ul> by using .after instead of .append

You’re right - instead, save it in a variable:

var a, ul = $('#teeTimeList');
$.each(msg.d, function(index, value) {
  a = $('<a href="#" class="' + value.Availability + '" title="' + value.Time + '">' + value.Time + ' - ' + value.Availability + '</a>');
  a.click(function(event) {
    event.preventDefault(); //stop the link from going to href
    TeeTimeSelected(this);
  });
  $('<li></li>').append(a).appendTo(ul);
});

>> “You should be able to get rid of the <ul> by using .after instead of .append”

How’s that?

An even better solution may be to give the ul in the jQuery code the same identifer, and at the end replace the old one with the new one.


var $teeTimeList = $('<ul id="teeTimeList">');
...
$('#teeTimeList').replaceWith($teeTimeList);

.replaceWith($teeTimeList);

Wow Paul, that was thinking outside of the box. Good one. But, I can’t help but wonder how expensive .replaceWith is? I mean .html() is simply innerHTML. What does jQuery have to do under the hood to do .replaceWith()?

I don’t see why you need to replace the UL at all. Why not just fill the existing UL with <li> items?

@Tommy - that’s what I was originally doing. Keep in mind each time the method is called we have to replace the list items with new ones. Which is why .html() works so well and appendTo() will not.

When jQuery has the information in $teeTimeList is is already an object. Using html means converting the objects to text, and then the browser converting them to objects once again.

You’re welcome to speed test the differences, but the difference is so small that you will not be capable of determining the difference when comparing the two side by side.

OK… I see now. You could also just do $(‘#teeTimeList’).empty() before refilling, but replacing the UL is just as good.