Question

I am trying to dynamically populate and set collapse/expand handlers for a collapsible list in jQuery Mobile. The expand handler is working as expected but the collapse handler triggers once for every item on the list when an element is expanded.

<head>
    <link rel="stylesheet" href="jquery.mobile-1.2.0-alpha.1.css?gfd" />
    <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
    <script src="http://jquerymobile.com/demos/1.2.0-alpha.1/js/jquery.mobile-1.2.0-alpha.1.js"></script>
</head>
<script>
    $(document).ready(function () {

        for (var i = 0; i < 4; i++) {

            var element = $("#listElementTemplate").clone();

            element.find('h3').append("list Element: " + i);
            $("#list").append(element);

            element.on('expand', function () {
                alert("expand: "+i);
            });

            element.collapsible();

            element.on('collapse', function () {
                alert("collapse: "+i);
            });
        }
    });
</script>

<body>
    <div id='listElementTemplate' data-role="collapsible" data-collapsed='true'>
            <h3 class='chart-elem-data'>
    </h3>

        <p id=''>Content</p>
    </div>
    <div data-role="page" class="type-interior">
        <div data-content-theme="c" id="list" data-role="collapsible-set"></div>
    </div>
</body>

Was it helpful?

Solution

I'm not crazy about this solution but what I've done is created a unique name attribute for each list element, then on the expand event I set a variable equal to the unique name attribute of the expanded element. Then I use condition logic in the collapse handler so code only fires if the name of the collapsing element is equal to that of the previously expanded element.

It's not pretty but it seems to work.

 $(document).ready(function () {
   //Create element name variable
   var elementName;
    for (var i = 0; i < 4; i++) {
        (function (i) {
            var element = $("#listElementTemplate").clone();
            //Use index to create unique name attribute
            element.attr("name",count);
            element.find('h3').append("list Element: " + i);
            $("#list").append(element);

            element.on('expand', function () {
                //On expand set element name to name of expanded element
                elementName = $(this).attr("name");
            });

            element.collapsible();

            element.on('collapse', function(){
                      //Use conditional logic only trigger code on the previously expanded element
              if (elementName == $(this).attr("name")){
                      //code to execute
              }else{
                          //Leave empty
                           }
    });
    }
});

OTHER TIPS

This behavior is not an error.

Think about it you have a collapsible-set with 4 collapsibles. Only one can be expanded at the same time. So when one is expanded other will trigger collapse event. I repeat, this is a set so they act as a set.

If you don't want them to behave like that then you will need to have a collapsible-set for every collapsible element. But in this case if you expend another collapsible first one will still stay collapsed.

Working example: http://jsfiddle.net/Gajotres/AXhkF/

HTML :

<!DOCTYPE html>
<html>
    <head>
        <title>jQM Complex Demo</title>
        <meta http-equiv='Content-Type' content='text/html; charset=utf-8'/>    
        <meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0; minimum-scale=1.0; user-scalable=no; target-densityDpi=device-dpi"/>
        <link rel="stylesheet" href="http://code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.css" />
        <script src="http://code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.js"></script>      
    </head>
    <body>  
        <div data-content-theme="c" id="list" data-role="collapsible-set">
            <div id='listElementTemplate' data-role="collapsible" data-collapsed='true'>
                <h3 class='chart-elem-data'></h3>
                <p id=''>Content</p>
            </div>
        </div>        
        <div data-role="page" id="type-interior">

        </div>      
    </body>
</html>    

JS :

$(document).on('pagebeforeshow', '#type-interior', function(){       
    for (var i = 0; i < 4; i++) {
        var element = $("#list").clone().attr('id','list'+i);
        element.find('[data-role="collapsible"]').attr('id','element'+i);
        element.find('h3').append("list Element: " + i);
        element.appendTo('[data-role="page"]');

        $(document).on('expand', '#element'+i ,function (e) {
            if(e.handled !== true) // This will prevent event triggering more then once
            {
                console.log('expand = '+  $(this).attr('id'));
                e.handled = true;
            }
        });

        $(document).on('collapse', '#element'+i,function (e) {
            if(e.handled !== true) // This will prevent event triggering more then once
            {            
                console.log('collapse = ' + $(this).attr('id'));
                e.handled = true;
            }
        });

        $('#element'+i).collapsible();        
    }        
});

Again you can manually collapse all other collapsibles during the expend event but then you will face same situation as in your example.

Basically there isn't anything you can do here.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top