Search code examples
javascripttabulator

Is it possible to replace the data in a table that has a data tree without automatically collapsing/expanding the tree?


I'm trying to create a table that can be edited by the user in a web application. The table has several data trees in it. Every time the user edits something in the table, table.replaceData(data) is called on the table. The idea of replaceData is that it will "silently" replace all of the data in the table without changing the scroll position, sort or filtering..., however, it will also reset the expansion state of all data trees in the table to their initial state. That is, if dataTreeStartExpanded === true, then calling replaceData will expand all of the data trees in the table. If dataTreeStartExpanded === false, then calling replaceData will collapse all data trees in the table. This is undesirable because the user might be editing a child element of one of those data trees, and if they want to see their change, or move on to the next element to change, they have to manually re-expand the data tree every time they make a change.

This is using Tabulator version 4.2.1. I've already tried clearing the table, then calling setData or replaceData but, of course, this results in the same problem. I get the feeling that this problem could be solved by using the updateData method, but I'm trying to avoid that as our rows don't have indices, and adding them would require backend changes or strange data manipulation in JS.

Here is a brief code snippet:

const table = new Tabulator('#table', {
  dataTree: true,
  dataTreeStartExpanded: false,
  columns: [
    {title: 'Name', field: 'name',},
    {title: 'Age', field: 'age',},
  ],
  data: someDataWithNestedElements,
})

button.onclick = () => {table.replaceData(otherDataWithNestedElements)};

Where someDataWithNestedElements is a properly formatted JS array with a _children property for Tabulator's dataTree, and otherDataWithNestedElements is a very similar, but slightly different set of data. Even if one of the data trees is expanded at the time the button is clicked, it will collapse after the button is clicked because dataTreeStartExpanded is set to false.

Here's a JSFiddle with a more fleshed-out and live example.

I would expect replaceData to preserve the expansion state of a data tree, much like it preserves scroll position, sorting, and filtering. Instead, it expands/collapses data trees automatically depending on the truth value of dataTreeStartExpanded.


Solution

  • Use reactivity

    // Original table for the data
    let someTableData = [{
      name: 'Quiz #1',
      date: '2019-07-06',
      _children: [{
        name: 'What is your name?',
        answer: 'Sir Lancelot of Camelot',
      }, {
        name: 'What is your quest?',
        answer: 'To seek the Holy Grail',
      }, {
        name: 'What is your favorite color?',
        answer: 'Red',
      }, ],
    }, {
      name: 'Quiz #2',
      date: '2019-08-01',
      _children: [{
        name: 'What is the air speed velocity of an unladen swallow?',
        answer: '24 mph',
      }, {
        name: 'African or European?',
        answer: 'I don\'t know that!',
      }, ],
    }, ];
    
    
    // The Tabulator table itself
    const myTable = new Tabulator('#table', {
      dataTree: true,
      //dataTreeStartExpanded: true, //Uncomment this line to see the trees expand themselves when the button is pressed
      data: someTableData,
      layout: 'fitColumns',
      reactiveData: true,
      columns: [{
          title: 'Quiz',
          field: 'name',
        },
        {
          title: 'Answer Key',
          field: 'answer',
        },
        {
          title: 'Due date',
          field: 'date',
        },
      ],
    });
    
    // Toggle between the two data sets when the button is clicked
    let replaced = false;
    const replaceData = () => {
    
      someTableData[1]._children[0].answer = '200 mph';
    
      if (replaced === false) {
        // myTable.replaceData(someOtherData);
        replaced = true;
      } else {
        // myTable.replaceData(someTableData);
        replaced = false;
      }
    }
    
    document.querySelector('button').onclick = replaceData;
    <!DOCTYPE html>
    <html>
    
    <head>
      <!-- Tabulator CDN -->
      <link href="https://unpkg.com/[email protected]/dist/css/tabulator.min.css" rel="stylesheet">
      <script type="text/javascript" src="https://unpkg.com/[email protected]/dist/js/tabulator.min.js"></script>
      <title>Tabulator Tree Demo</title>
    </head>
    
    <body>
      <h3>Table 1</h3>
      <button type='button'>Click me to replace 24 mph to 200mph silently</button>
      <div id='table'></div>
    
    
    </body>
    
    </html>