title: Problems with collapsible/expandable nested table rows
body: <p>I'm trying to create a table that has a structure like this:</p>
  
  <pre><code>Project
  --Category
  ----File
  ----File
  ----File
  --Category
  ----File
  Project
  --Category
  ----File
  ----File
  </code></pre>
  
  <p>The code that creates the table uses PHP to get the data from a database and looks like this: </p>
  
  <pre><code>&lt;table&gt;
          &lt;thead&gt;
            &lt;tr class="table-row" tabindex="1"&gt;
              &lt;th class="fixed-header"&gt;&lt;/th&gt;
              &lt;th&gt;Dateiname&lt;/th&gt;
              &lt;th&gt;Benutzer&lt;/th&gt;
              &lt;th&gt;Erstelldatum&lt;/th&gt;
              &lt;th&gt;Änderungsdatum&lt;/th&gt;
              &lt;th&gt;Erste Zeile&lt;/th&gt;
            &lt;/tr&gt;
          &lt;/thead&gt;
          &lt;?php
          include_once('connect.php');
  
          //loop projects
          $resultProjects = $connect-&gt;query("SELECT project.name, project.idProject FROM project,user,user_has_project WHERE user.idUser = user_has_project.user_idUser AND user_has_project.project_idProject = project.idProject AND user.idUser = '".$_SESSION['userid']."'");
          if($resultProjects-&gt;num_rows &gt; 0) {
            echo "&lt;tbody&gt;";
            while($row = $resultProjects-&gt;fetch_assoc()) {
              $resultProjectID = $row['idProject'];
              echo "&lt;tr class='".$row['idProject']." table-row project-marker' tabindex='1'&gt;";
              echo "&lt;th&gt;&lt;img src='images/arrow_right.gif' class='expand expandProjectBtn'&gt;&lt;img src='images/arrow_down.gif' class='collapse collapseProjectBtn'&gt;&lt;/th&gt;";
              echo "&lt;td class='table-project'&gt;".$row['name']."&lt;/td&gt;";
              echo "&lt;td&gt;&lt;/td&gt;";
              echo "&lt;td&gt;&lt;/td&gt;";
              echo "&lt;td&gt;&lt;/td&gt;";
              echo "&lt;td&gt;&lt;/td&gt;";
              echo "&lt;/tr&gt;";
  
              //loop categories
              $resultCategories = $connect-&gt;query("SELECT category.name, category.idCategory FROM category,user,user_has_category WHERE user.idUser = user_has_category.user_idUser AND user_has_category.category_idCategory = category.idCategory AND user.idUser = '".$_SESSION['userid']."'");
              if($resultCategories-&gt;num_rows &gt; 0) {
                while($row = $resultCategories-&gt;fetch_assoc()) {
                  $resultCategoryID = $row['idCategory'];
                  echo "&lt;tr class='".$row['idCategory']." table-row category-marker' tabindex='1'&gt;";
                  echo "&lt;th&gt;&lt;img src='images/arrow_right.gif' class='expand toggleCategoryBtn'&gt;&lt;img src='images/arrow_down.gif' class='collapse toggleCategoryBtn'&gt;&lt;/th&gt;";
                  echo "&lt;td class='table-category'&gt;".$row['name']."&lt;/td&gt;";
                  echo "&lt;td&gt;&lt;/td&gt;";
                  echo "&lt;td&gt;&lt;/td&gt;";
                  echo "&lt;td&gt;&lt;/td&gt;";
                  echo "&lt;td&gt;&lt;/td&gt;";
                  echo "&lt;/tr&gt;";
  
                  //loop files
                  $resultFiles = $connect-&gt;query("SELECT file.name AS 'filename', file.description AS 'filedescription', category.name AS 'categoryname', project.name AS 'projectname', user.name AS 'username', idFile, createDate, editDate
                    FROM file JOIN file_has_project ON idFile = file_has_project.file_idFile
                              JOIN file_has_category ON idFile = file_has_category.file_idFile
                              JOIN project ON idProject = file_has_project.project_idProject
                              JOIN category ON idCategory = file_has_category.category_idCategory
                              JOIN user_has_project ON idProject = user_has_project.project_idProject
                              JOIN user_has_category ON idCategory = user_has_category.category_idCategory
                              JOIN user ON idUser = user_has_category.user_idUser
                              WHERE user.idUser = '".$_SESSION['userid']."' AND idCategory = '".$resultCategoryID."' AND idProject = '".$resultProjectID."'
                              ORDER BY file.name ASC");
                  if ($resultFiles-&gt;num_rows &gt; 0) {
                    while($row = $resultFiles-&gt;fetch_assoc()) {
                      echo "&lt;tr class='".$row['idFile']." table-row file-marker' tabindex='1' draggable=true&gt;";
                      echo "&lt;th class='table-edit-button fixed-header'&gt;&lt;img src='images/open.gif' /&gt;&lt;/th&gt;";
                      echo "&lt;td class='table-file'&gt;".$row['filename']."&lt;/td&gt;";
                      echo "&lt;td&gt;".$row['username']."&lt;/td&gt;";
                      echo "&lt;td&gt;".$row['createDate']."&lt;/td&gt;";
                      echo "&lt;td&gt;".$row['editDate']."&lt;/td&gt;";
                      echo "&lt;td&gt;".$row['filedescription']."&lt;/td&gt;";
                      echo "&lt;/tr&gt;";
                    }
                  }
                }
              }
            }
            echo "&lt;/tbody&gt;";
          }
          ?&gt;
        &lt;/table&gt;
  </code></pre>
  
  <p>The database ID's that get written in the rows as the first class are used so that I can determine which row got clicked. But that's not really important for the problem I'm having.</p>
  
  <p>The problem is as follows: I can collapse the categories so that the files get hidden. And I can collapse the projects so that the categories together with the files get hidden. But when I collapse a category first and then collapse the project which the category belongs to and expand it afterwards the files get toggled again. But I want that the files stay hidden when I expand a project which has a collapsed category in it.</p>
  
  <p>This is the code I use to collapse and expand categories and projects (it's wrapped by a <code>$(document).ready(function() {});</code>:</p>
  
  <pre><code>function toggleTableCategory() {
      var className = $(this).closest('tr').next().attr('class').split(' ')[2];
      var element = $(this).closest('tr').next();
  
      while(className == 'file-marker') {
        element.toggle();
        element = element.next();
        className = element.attr('class').split(' ')[2];
      }
  
      $(this).closest('tr').find('img').toggle();
    }
  
    function collapseTableProject() {
      $(this).closest('tr').nextUntil('.project-marker', ':visible').toggle();
      $(this).closest('tr').find('img').toggle();
    }
  
    function expandTableProject() {
      $(this).closest('tr').nextUntil('.project-marker').toggle();
      $(this).closest('tr').find('img').toggle();
    }
  
    $(document).on("click", ".toggleCategoryBtn", toggleTableCategory);
    $(document).on("click", ".expandProjectBtn", expandTableProject);
    $(document).on("click", ".collapseProjectBtn", collapseTableProject);
  </code></pre>
  
  <p>The code to collapse the categories seems to be overly complicated. I tried using <code>.nextUntil('.category-marker')</code> but with this I had a problem where it also toggled the next project row when I toggled the last category of a project, so I had to do it this way.</p>
  
  <p>My final question now is: How can I save the state of the collapsed categories so that they collapsed when I expand a project.</p>
  
  <p>Additional question: It is possible to move the files from category to category and from project to project via drag&amp;drop. To give the user immediate feedback I do an AJAX call when this happens and draw the table new. It would be great to save the state of the toggled categories and projects for that too. But I have no idea how to approach this because the table is always created with PHP and fed with data from a MySQL database.</p>
  
  <p>If you need anymore information to help me let me know and I will edit it in.</p>