atatanasov / gijgo

Gijgo - Free Javascript Controls
http://gijgo.com
MIT License
475 stars 187 forks source link

getCheckedNodes is not a function if tree is in a modal #717

Closed exitlol closed 1 year ago

exitlol commented 1 year ago

I have an issue, where my treeview is instantiated inside a bootstrap modal. When I frist open the modal everything works correctly. If I close said modal, then reopen it, the already checked boxes are there which is fine, but if I check/uncheck a checkbox I get a console error saying that getCheckedNodes is not a function.

I've tried assign tree both to a const inside a function and globally.

The issue is for some reason after the modal re-open tree loses the method mentioned in the title.

HTML structure:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
    <link
      rel="stylesheet"
      href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css"
      integrity="sha384-xOolHFLEh07PJGoPkLv1IbcEPTNtaed2xpHsD9ESMhqIYd0nLMwNLD69Npy4HI+N"
      crossorigin="anonymous"
    />
    <script
      src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js"
      integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj"
      crossorigin="anonymous"
    ></script>
    <script
      src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"
      integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN"
      crossorigin="anonymous"
    ></script>
    <script
      src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/js/bootstrap.min.js"
      integrity="sha384-+sLIOodYLS7CIrQpBjl+C7nPvqq+FbNUBDunl/OZv93DB7Ln/533i8e/mZXLi/P+"
      crossorigin="anonymous"
    ></script>
    <script
      src="https://unpkg.com/gijgo@1.9.14/js/gijgo.min.js"
      type="text/javascript"
    ></script>
    <link
      href="https://unpkg.com/gijgo@1.9.14/css/gijgo.min.css"
      rel="stylesheet"
      type="text/css"
    />
    <link
      href="https://fonts.googleapis.com/icon?family=Material+Icons"
      rel="stylesheet"
    />
    <title>Document</title>
  </head>
  <body>
    <script type="text/javascript" src="src/index.js"></script>
    <main>
      <div class="container">
        <h3 class="mb-4">treeview fiddle</h3>
        <div class="row">
          <div class="col-10">
            <input class="w-100" type="text" name="treeview" id="treeview" />
          </div>
          <div class="col-2">
            <button
              type="button"
              class="btn btn-primary"
              id="btn-modal-toggle"
              data-toggle="modal"
              data-target="#exampleModal"
              onclick="onModalToggle()"
            >
              Választ
            </button>
          </div>
        </div>
      </div>
    </main>

    <!-- Button trigger modal -->

    <!-- Modal -->
    <div
      class="modal fade"
      id="exampleModal"
      tabindex="-1"
      aria-labelledby="exampleModalLabel"
      aria-hidden="true"
    >
      <div class="modal-dialog">
        <div class="modal-content">
          <div class="modal-header">
            <h5 class="modal-title" id="exampleModalLabel">Modal title</h5>
            <button
              type="button"
              class="close"
              data-dismiss="modal"
              aria-label="Close"
            >
              <span aria-hidden="true">&times;</span>
            </button>
          </div>
          <div class="modal-body">
            <input type="text" name="treeviewSearch" id="treeviewSearch" />
            <div id="tree"></div>
          </div>
          <div class="modal-footer">
            <button
              type="button"
              class="btn btn-secondary"
              data-dismiss="modal"
            >
              Close
            </button>
            <button type="button" class="btn btn-primary">Save changes</button>
          </div>
        </div>
      </div>
    </div>
  </body>
</html>

main JS file

function onModalToggle() {
  const treeviewInput = document.querySelector('#treeview');
  const modal = document.querySelector('#exampleModal');
  const treeviewSearchInput = document.querySelector('#treeviewSearch');
  // console.log(treeviewInput, modal, treeviewSearchInput);
  fetchData();
}

function fetchData() {
  fetch('src/assets/data/get-user-interests-categories.json').then(response => response.json()).then(resp => createTreeviewFromData(resp.categories));
}

function remapDataToTreeView(data) {
  return  {
    text: data.title,
    categoryId: data.categoryId,
    children: data?.child?.length > 0 ? data.child.map(c => remapDataToTreeView(c)) : [],
    parentCategoryId: data.parentCategoryId,
  }
}

function createTreeviewFromData(data) {
  data = data.map(d => remapDataToTreeView(d));
  dataSource = data;
  tree = $('#tree').tree({
    primaryKey: 'categoryId',
    uiLibrary: 'bootstrap4',
    dataSource: data,
    checkboxes: true,
    icons: {
      expand: '<i class="material-icons">chevron_right</i>',
      collapse: '<i class="material-icons">expand_more</i>'
  }
  });
  tree.on('checkboxChange', (e, $node, record, state) => onTreeCheckboxChange(e, $node, record, state));
}

function onTreeCheckboxChange(e, $node, record, state) {
  console.log(tree);
  const checked = tree.getCheckedNodes();
  const parentCategories = dataSource.filter(cat => cat.parentCategoryId === 0);
  console.log(checked);

// fiddle with checked ids that clearly not in the scope of the issue
}

NOTE: I am new to jQuery (mainly I learned Angular so I am unfamiliar how Jquery handles stuff in the background), if it's a main jQuery issue let me know.

atatanasov commented 1 year ago

"tree" needs to be declared as global variable accessible by the onTreeCheckboxChange function. I think that you don't have access to this variable in that function.