CodeIgniter Forums
[jQuery] 3-level dynamic menu troubles - Printable Version

+- CodeIgniter Forums (https://forum.codeigniter.com)
+-- Forum: Archived Discussions (https://forum.codeigniter.com/forumdisplay.php?fid=20)
+--- Forum: Archived Development & Programming (https://forum.codeigniter.com/forumdisplay.php?fid=23)
+--- Thread: [jQuery] 3-level dynamic menu troubles (/showthread.php?tid=14504)



[jQuery] 3-level dynamic menu troubles - El Forum - 01-05-2009

[eluser]Phil Sturgeon[/eluser]
Posting a jQuery issue here as I know plenty of you are great with the framework. Well, that and I already have this forum bookmarked ;-)

I'm creating a 3 leveled dynamic menu system and the damn thing will be the death of me. It seems that HTML I load with JS (AJAX call returning JSON made into HTML with jQuery) wont listen to the same rules as HTML loaded through a normal PHP echo.

Code:

Code:
<h2>Browse</h2>

<ul id="submenu">
    
    &lt;? foreach($this->geolocation_m->getCountries(array('has_profiles'=>true)) as $country): ?&gt;
    <li>
        &lt;?=anchor('profiles/browse/country/'.$country->code, $country->name, array('id'=>'country-'.$country->id)); ?&gt;
        
        &lt;? if(isset($result_country) && $result_country->code == $country->code): ?&gt;
        <ul id="cities-&lt;?=$result_country->code; ?&gt;" class="populated">
            
            &lt;? foreach($menu_cities as $city): ?&gt;
            <li><a >id ?&gt;" href="[removed]void(0);&lt;?//=site_url('profiles/browse/city/'.$city->id); ?&gt;">&lt;?=$city->name; ?&gt; (&lt;?=$city->profile_count;?&gt;)</a></li>
            &lt;? endforeach; ?&gt;
            
        </ul>
        
        &lt;? endif; ?&gt;
    </li>
    &lt;? endforeach; ?&gt;
    
</ul>

[removed]
$(function() {

    $("ul#submenu li a[id^='country-']").click(function() {
        
        // Hide all other populated lists
        $(this).parent('li').siblings('li').children('ul.populated').slideUp();
        
        // If this country already has a list of cities, then show it
        if($(this).siblings('ul').children('li').length > 0) {
            $(this).siblings('ul').slideDown();
        
        // Not yet populated, get the data
        } else {

            // Get UK from country-UK
            country = this.id.replace('country-', '')
        
            // Set a new list element. Eg, country-UK clicked sets new ul as cities-UK
            city_list = $('<ul/>').attr('id', 'cities-' + country).addClass('populated');
            
            populate_city_list(city_list, country, '<a/>');
            
            $(this).parent().append(city_list);
            
        }
        
        return false;
    });
    
    // Populate activities
    $("a[id^='city-']").click(function() {
        
        // Set all other populated lists to be hidden
        $(this).parent('li').siblings('li').children('ul.populated').slideUp();
        
        // If this country already has a list of cities, then show it
        if($(this).siblings('ul').children('li').length > 0) {
            $(this).siblings('ul').slideDown();

        // Not yet populated, get the data
        } else {
        
            // Get 2342 from city-2342
            city = this.id.replace('city-', '')

            // Set a new list element. Eg, city-2342 clicked sets new ul as activities-2342
            activity_list = $('<ul/>').attr('id', 'activities-' + city).addClass('populated');
            
            populate_activities_list(activity_list, city, '<a/>');
            
            $(this).parent().append(activity_list);
            
        }
        
        return false;
    });
    
});
[removed]


This is not the cleanest code here, but I have reason for my madness.

Anyway, it loads a list of countries with a normal PHP loop, and can possibly show cities if some have already been selected in PHP.

Normally a user will click a cuntry, be shown a list of cities, then should be shown a list of activities.

INSTEAD what happens is a user clicks a country, is shown a list of cities then when they click one, instead of the jQuery rule being listened to, it takes them to the city result page. They click again on the same city and THEN they are shown the list of activities.

Any idea how I can get my dynamically inserted HTML playing by the same rules?


[jQuery] 3-level dynamic menu troubles - El Forum - 01-05-2009

[eluser]xwero[/eluser]
For dynamically inserted html you best use the livequery plugin.

I'm not sure but i believe it will be a part of jQuery in 1.3.


[jQuery] 3-level dynamic menu troubles - El Forum - 01-05-2009

[eluser]Phil Sturgeon[/eluser]
Let's hope so, seems like a silly feature to miss out on. Thanks for the link dude.


[jQuery] 3-level dynamic menu troubles - El Forum - 01-05-2009

[eluser]Pascal Kriete[/eluser]
You need to attach the event handler dynamically.

Code:
&lt;script type="text/javascript">
$(function() {

    $("ul#submenu li a[id^='country-']").click(function() {
        
        // Hide all other populated lists
        $(this).parent('li').siblings('li').children('ul.populated').slideUp();
        
        // If this country already has a list of cities, then show it
        if($(this).siblings('ul').children('li').length > 0) {
            $(this).siblings('ul').slideDown();
        
        // Not yet populated, get the data
        } else {

            // Get UK from country-UK
            country = this.id.replace('country-', '')
        
            // Set a new list element. Eg, country-UK clicked sets new ul as cities-UK
            city_list = $('<ul/>').attr('id', 'cities-' + country).addClass('populated');
            
            populate_city_list(city_list, country, '<a/>');
            
            $(this).parent().append(city_list);
            
        }

        // Add the event handler for the new city_list
        observe_city_list();
        
        return false;
    });
    
    // Populate activities
    observe_city_list = function() {
        $("a[id^='city-']").click(function() {
        
            // Set all other populated lists to be hidden
            $(this).parent('li').siblings('li').children('ul.populated').slideUp();
        
            // If this country already has a list of cities, then show it
            if($(this).siblings('ul').children('li').length > 0) {
                $(this).siblings('ul').slideDown();

            // Not yet populated, get the data
            } else {
        
                // Get 2342 from city-2342
                city = this.id.replace('city-', '')

                // Set a new list element. Eg, city-2342 clicked sets new ul as activities-2342
                activity_list = $('<ul/>').attr('id', 'activities-' + city).addClass('populated');
            
                populate_activities_list(activity_list, city, '<a/>');
            
                $(this).parent().append(activity_list);
            
            }
        
            return false;
        });
    }
});
&lt;/script>

I'm sure you could make this more efficient as well (by listening to clicks on the container instead of listening on each link), but that should do it.


[jQuery] 3-level dynamic menu troubles - El Forum - 01-06-2009

[eluser]Phil Sturgeon[/eluser]
I was considering that method but wasnt sure if it would work. By wrapping the entire chunk of code in one container I can assign it statically and dynamically. Doh!


[jQuery] 3-level dynamic menu troubles - El Forum - 01-06-2009

[eluser]Phil Sturgeon[/eluser]
Thinking about it, the method you have used is no different to inserting my second function in the ELSE of the first function, and thats sadly something I tried already.

The livequery seemed to work fine, but sadly doesn't support functions like toggle(). :-(