Can't change elements added during $(document).ready during $(document).ready

258 Views Asked by At

I've implemented a page with a list of options (job categories) that when clicked should display data (job descriptions). I am using BBQ to handle the back stack.

Everything works dandy, except for setting the initial selection when the user first navigates to the page. My code is getting called to addClass('selected') to the right element but it is like that element is not actually available when the code runs.

Note that I added a debug call $('#category' + C).append('bite me'); to prove to myself this was NOT a problem with the stylesheet/CSS.

Here's my code:

<script>
    function historyCallback(e) {
        var C = $.bbq.getState("category");
        if (C != undefined && C != 0) {
            // We've been navigated back to
            $('#Descriptions').empty();
            $.getJSON('/Jobs/GetJobDescriptions?' + 'JobCategory=' + C, function(descs) {
                $.each(descs, function(index, description) {
                    $('#Descriptions').append('<h3><a href="/Jobs/ShowJob?JobID=' + description.ID + '">' + description.JobTitle + '</a></h3>');
                    $('#Descriptions').append('<p>' + description.JobSummary + '</p>');
                    $('#Descriptions').append('<p><a href="/Jobs/ShowJob?JobID=' + description.ID + '">Read more...</a></p>');
                });
            });    
            $('a.jobcat').removeClass('selected');
            $('#category' + C).addClass('selected');
            $('#category' + C).append('bite me');
        }
        else { // category not specified so reset the page
            $.bbq.pushState({ category: 3 },2);
        }
    }

    function loadCategories() {
        $.getJSON('/Jobs/GetCategories', function(data) {
            var categories = data;
            $.each(categories, function(index, category) {
                addCategory(category.ID, category.CategoryName);
            });
        });
    }

    function addCategory(CatID, Name) {
        $('#Categories').append('<p><a class="jobcat" id="category' + CatID + '">' + Name + '</a></p>');
        $('#category' + CatID).click(function(event) {
            $.bbq.pushState({ category: CatID }, 2); // merge_mode=2 means wipe out
        });
    }

    $(document).ready(function () {
        $(window).bind("hashchange", historyCallback); // needed for bbq plugin to work     
        loadCategories();
        historyCallback(); 
    });   
 </script>

The first time through historyCallback, called directly from $(document).ready, C is undefined and thus the else statement executes $.bbq.pushState({ category: 3 },2); which sets the #has to category=3 which is my default category.

This causes historyCallback to be called again, this time with C == 3. The three lines at the end of the if clause have no effect:

$('a.jobcat').removeClass('selected');
$('#category' + C).addClass('selected');
$('#category' + C).append('bite me');

Note these lines DO work as expected when I click on a category.

It seems like the #category anchors created in loadCategories() are not yet available to jQuery/DOM/whatever when this code runs.

Do I need some sort of delay ore something? What am I missing?

Thanks a ton.

2

There are 2 best solutions below

2
On BEST ANSWER

Looks to me like the problem is timing - you can't guarantee that the elements have been created, since they depend on whether the JSON has loaded and the related function has executed. Your code will almost certainly call historyCallback() before addCategory() ever executes. I'm not familiar with BBQ, though.

0
On

It's isn't available because the getJSON function runs asynchronously. The getJSON callback happens after the json data arrives from the server.

Don't use a delay. What might work better:

  1. Put the category selection into the callbacks.
  2. Trigger a custom event when your categories are loaded, then bind an event listener the makes your selection after.