Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to properly sort multiple accordions with jQuery

This is my first time posting so please let me know if I fail to provide enough details.

I have a page that contains multiple accordions. I wanted to use multiple accordions because I wanted users to be able to have multiple sections open at once which is not native to accordion.

I also want users to be able to sort those accordions. The way the page is currently set up, users can sort the accordion with no problems.

When the user goes to sort the accordions, I have a script that will close all existing accordions, store their ids in an array, and then reopen them when the user is done sorting. That part works fine too.

The problem occurs when you try to place the section you are sorting between two sections that were previously open. It does not appear that jQuery can easily tell where one section begins and one ends when they are closed programatically. Note that if they were already closed, it works as expected.

I've tried several approaches to this problem including adding a spacer div between sections as well as destroying the accordions and then reinitializing them after the sorting is finished to no avail.

I suspect the problem occurs because when the accordion is first grabbed, the sections are open. But at that point, I close all the sections and even though the section closes, it causes those sections to jump around sporadically when you try to put a section between two.

I've also noticed that the height of the contents of the accordion factors in. In my example below, the first div causes problems when it is open and you try to sort them but the others less so.

Here is the code I have. The jQuery is the basic jQuery library and the stuff I wrote I included inline for simplicity:

<html>
<head>
<link href="/css/flick/jquery-ui.css" media="screen" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="/js/jquery.js"></script>
<script type="text/javascript" src="/js/jquery-ui.js"></script>
<script type="text/javascript">
  $(document).ready(function() {
    // Add Accordion stuff
    $(".accordion").accordion({
      autoHeight: false,
      active: false,
      collapsible: true
    }); // end $(".accordion").accordion

    // Add sortables
    $('.sortable').sortable({
      start: function(e, ui) {
        container = $(e.target);

        var parent_id = container.parent().parent().attr('id');
        expanded_ones = new Array();
        var count = 0;
        var summary = '';
        var child = '';
        var active = '';

        // now close all other sections
        $.each($('#' + parent_id + ' .accordion'), function() {
          // get the child element since that has the div id I need
          child = $(this).children('div');

          // get the active information to see if it is open or closed
          active = $(this).accordion('option', 'active');

          // check to see if this one is expanded
          if(parseInt(active) == active) {
            // store this id so we can open it later
            expanded_ones[count] = $(child).attr('id');
            count++;

            // and close the accordion
            $(this).accordion({ active: false });
          } // end if(parseInt(active) == active)
        }); // end $.each($('#' + parent_id + ' .accordion'), function()
      }, // end start: function(e, ui)
      stop: function(e, ui) {
        container = $(e.target);

        var parent_elem = '';

        // expand the ones that were originally expanded
        for(var i = 0; i < expanded_ones.length; i++) {
          parent_elem = $('#' + expanded_ones[i]).parent();
          $(parent_elem).accordion('option', 'active', 0);
        } // end for(var i = 0; i < expanded_ones; i++)
      } // end stop: function(e, ui)
    }); // end $('.sortable').sortable
  }); // end $(document).ready(function() {
</script>
</head>
<body>
<div id="outer">
  <div class="box">
    <div class="accordion_wrapper sortable" rel="sections">
      <div id="accordion_a" class="section_accordion">
        <div class="accordion">
          <h4>Accordion A</h4>
          <div id="accordion_a_content">
            <p>Stuff</p>
            <p>Stuff</p>
            <p>Stuff</p>
            <p>Stuff</p>
            <p>Stuff</p>
            <p>Stuff</p>
            <p>Stuff</p>
            <p>Stuff</p>
            <p>Stuff</p>
            <p>Stuff</p>
            <p>Stuff</p>
            <p>Stuff</p>
            <p>Stuff</p>
            <p>Stuff</p>
            <p>Stuff</p>
            <p>Stuff</p>
            <p>Stuff</p>
            <p>Stuff</p>
            <p>Stuff</p>
            <p>Stuff</p>
            <p>Stuff</p>
            <p>Stuff</p>
            <p>Stuff</p>
            <p>Stuff</p>
            <p>Stuff</p>
            <p>Stuff</p>
            <p>Stuff</p>
            <p>Stuff</p>
            <p>Stuff</p>
            <p>Stuff</p>
            <p>Stuff</p>
            <p>Stuff</p>
            <p>Stuff</p>
            <p>Stuff</p>
            <p>Stuff</p>
            <p>Stuff</p>
          </div>
        </div>
      </div>

      <div id="accordion_b" class="section_accordion">
        <div class="accordion">
          <h4>Accordion B</h4>
          <div id="accordion_b_content">
            Stuff
          </div>
        </div>
      </div>

      <div id="accordion_c" class="section_accordion">
        <div class="accordion">
          <h4>Accordion C</h4>
          <div id="accordion_c_content">
            Stuff
          </div>
        </div>
      </div>

      <div id="accordion_d" class="section_accordion">
        <div class="accordion">
          <h4>Accordion D</h4>
          <div id="accordion_d_content">
            Stuff
          </div>
        </div>
      </div>
    </div>
  </div>
    </div>
  </body>
</html>
like image 847
lokisapocalypse Avatar asked Feb 22 '11 17:02

lokisapocalypse


1 Answers

Firstly i would say, does this really need to be in accordians or sortable? Secondly i set up your example here. Using this example the sortable can send the page all over the place especially when accordian A is open. This can be extremely confusing to some users. I would recommend finding another option to complete your task.

From jQueries website API on Accordian

NOTE: If you want multiple sections open at once, don't use an accordion

An accordion doesn't allow more than one content panel to be open at the same time, and it takes a lot of effort to do that. If you are looking for a widget that allows more than one content panel to be open, don't use this. Usually it can be written with a few lines of jQuery instead, something like this:

 $(document).ready(function(){
    $('.accordion .head').click(function(){
        $(this).next().toggle();
        return false;   
    }).next().hide(); 
  });

Or animated:

 $(document).ready(function(){
    $('.accordion .head').click(function() {
        $(this).next().toggle('slow');
        return false;
     }).next().hide();
 });

So i would recommend creating your own custom code if you want to have multiple accordians open that are sortable.

like image 67
Timothy Ruhle Avatar answered Nov 14 '22 23:11

Timothy Ruhle