【问题标题】:Merge and grouping table using JSON and JQuery使用 JSON 和 JQuery 合并和分组表
【发布时间】:2019-08-17 17:26:11
【问题描述】:

我在为表提供行跨度并根据父行对其进行分组时遇到问题。我已经尝试找到一些解决方案,但大多数解决方案是合并相同的值而不是将它们分组。

  var data = 
  [
    {
      "LEVEL_1": "LEVEL 1",
      "LEVEL_2": "LEVEL 1.1",
      "LEVEL_3": "LEVEL 1.1.1",
    },
    {
      "LEVEL_1": "LEVEL 1",
      "LEVEL_2": "LEVEL 1.2",
      "LEVEL_3": "LEVEL 1.2.1",
    },
     {
      "LEVEL_1": "LEVEL 1",
      "LEVEL_2": "LEVEL 1.2",
      "LEVEL_3": "LEVEL 1.2.2",
    },
    {
      "LEVEL_1": "LEVEL 2",
      "LEVEL_2": "LEVEL 2.1",
      "LEVEL_3": "LEVEL 2.1.1",
    },
    {
      "LEVEL_1": "LEVEL 2",
      "LEVEL_2": "LEVEL 2.1",
      "LEVEL_3": "LEVEL 2.1.2",
    },
    {
      "LEVEL_1": "LEVEL 2",
      "LEVEL_2": "LEVEL 2.2",
      "LEVEL_3": "LEVEL 2.2.1",
    },
    {
      "LEVEL_1": "LEVEL 2",
      "LEVEL_2": "LEVEL 2.2",
      "LEVEL_3": "LEVEL 2.2.2",
    }
  ];

  var tableStr = '';
  $.each(data, function(index, value) { 
    tableStr += '<tr>' + 
       '<td>'+value.LEVEL_1+'</td>'+
       '<td>'+value.LEVEL_2+'</td>'+
       '<td>'+value.LEVEL_3+'</td>'+
     '</tr>';
  }); 
  $('#user tbody').html(tableStr);
 table { 
      border-collapse: collapse;
    }

    td {
      padding: 20px; 
      border: 1px solid black; 
      text-align: center;
    }

    th {
      padding: 20px; 
      border: 1px solid black; 
      text-align: center;
    }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table id="user">
    <thead>
        <tr>
          <th>LEVEL 1</th>
          <th>LEVEL 2</th>
          <th>LEVEL 3</th>
        </tr>
        <tr>
        </tr>
    </thead>
    <tbody> 
    </tbody>
</table>

我期待的结果:


我总是找到一个结果,它在一开始就奏效了。但是当我添加另一个级别但相同的数据时,它总是看起来像这样

从 Ajax 请求提供的 JSON 数据已经这样给出了。我必须修改 JSON 数据并将它们分组吗?或者它可以使用给定的 JSON 数据来完成?如何使用 Jquery 和 JSON 数据来做到这一点?提前致谢

【问题讨论】:

标签: javascript jquery html json


【解决方案1】:

我有一个解决方案。它可能不是最优雅的,但它确实有效

首先,我将数据从 JSON 转换为嵌套对象,该对象计算较低级别项的出现次数。

第二步是遍历该嵌套对象并相应地创建表、tr 和 td,并将​​第 1 步中的计数值用作rowspan 属性值。

我什至不需要 jQuery,只需要 VanillaJS。

console.clear();

var data = [
  {
    LEVEL_1: "LEVEL 1",
    LEVEL_2: "LEVEL 1.1",
    LEVEL_3: "LEVEL 1.1.1"
  },
  {
    LEVEL_1: "LEVEL 1",
    LEVEL_2: "LEVEL 1.2",
    LEVEL_3: "LEVEL 1.2.1"
  },
  {
    LEVEL_1: "LEVEL 1",
    LEVEL_2: "LEVEL 1.2",
    LEVEL_3: "LEVEL 1.2.2"
  },
  {
    LEVEL_1: "LEVEL 2",
    LEVEL_2: "LEVEL 2.1",
    LEVEL_3: "LEVEL 2.1.1"
  },
  {
    LEVEL_1: "LEVEL 2",
    LEVEL_2: "LEVEL 2.1",
    LEVEL_3: "LEVEL 2.1.2"
  },
  {
    LEVEL_1: "LEVEL 2",
    LEVEL_2: "LEVEL 2.2",
    LEVEL_3: "LEVEL 2.2.1"
  },
  {
    LEVEL_1: "LEVEL 2",
    LEVEL_2: "LEVEL 2.2",
    LEVEL_3: "LEVEL 2.2.2"
  }
];

const transformData = (data) => {
  let t = {};

  data.forEach((item, index, source) => {
    let l1 = item.LEVEL_1,
        l2 = item.LEVEL_2,
        l3 = item.LEVEL_3;
    t[l1]                         = t[l1]                         || {text: l1, content: {}, count: 0};
    t[l1].content[l2]             = t[l1].content[l2]             || {text: l2, content: {}, count: 0};
    t[l1].content[l2].content[l3] = t[l1].content[l2].content[l3] || {text: l3, content: {}, count: 0};
    t[l1].count++
    t[l1].content[l2].count++
    t[l1].content[l2].content[l3].count++
  })
  return t;
}

const transformDataTable = (tdata) => {

  const table = document.createElement('table');

  for (l1 in tdata) {
    const td1 = document.createElement('th')
    td1.textContent = tdata[l1].text;
    td1.setAttribute('rowspan', tdata[l1].count)
    let done1 = false;

    for (l2 in tdata[l1].content) {
      const td2 = document.createElement('td')
      td2.textContent = tdata[l1].content[l2].text;
      td2.setAttribute('rowspan', tdata[l1].content[l2].count)
      let done2 = false;
      
      for (l3 in tdata[l1].content[l2].content) {
        const td3 = document.createElement('td')
        td3.textContent = tdata[l1].content[l2].content[l3].text;
        td3.setAttribute('rowspan', tdata[l1].content[l2].content[l3].count)
        const tr = document.createElement('tr')
        !done1 && tr.appendChild(td1) && (done1 = true);
        !done2 && tr.appendChild(td2) && (done2 = true);
        tr.appendChild(td3);
        table.appendChild(tr);
      }
    }
  }
  return table;
}


const tdata = transformData(data);
const table = transformDataTable(tdata);


document.body.appendChild(table)
table {
  border-collapse: collapse;
}

td,
th {
  padding: 20px;
  border: 1px solid black;
  text-align: center;
}

通过一些修改,您可以单独对每一列进行排序

console.clear();

var data = [
  {
    LEVEL_1: "LEVEL 3",
    LEVEL_2: "LEVEL 3.1",
    LEVEL_3: "LEVEL 3.1.1"
  },
  {
    LEVEL_1: "LEVEL 1",
    LEVEL_2: "LEVEL 1.1",
    LEVEL_3: "LEVEL 1.1.1"
  },
  {
    LEVEL_1: "LEVEL 1",
    LEVEL_2: "LEVEL 1.2",
    LEVEL_3: "LEVEL 1.2.1"
  },
  {
    LEVEL_1: "LEVEL 1",
    LEVEL_2: "LEVEL 1.2",
    LEVEL_3: "LEVEL 1.2.2"
  },
  {
    LEVEL_1: "LEVEL 2",
    LEVEL_2: "LEVEL 2.1",
    LEVEL_3: "LEVEL 2.1.1"
  },
  {
    LEVEL_1: "LEVEL 3",
    LEVEL_2: "LEVEL 3.1",
    LEVEL_3: "LEVEL 3.1.2"
  },
  {
    LEVEL_1: "LEVEL 2",
    LEVEL_2: "LEVEL 2.1",
    LEVEL_3: "LEVEL 2.1.2"
  },
  {
    LEVEL_1: "LEVEL 2",
    LEVEL_2: "LEVEL 2.2",
    LEVEL_3: "LEVEL 2.2.1"
  },
  {
    LEVEL_1: "LEVEL 2",
    LEVEL_2: "LEVEL 2.2",
    LEVEL_3: "LEVEL 2.2.2"
  },
  {
    LEVEL_1: "LEVEL 2",
    LEVEL_2: "LEVEL 2.2",
    LEVEL_3: "LEVEL 2.2.3"
  }
  
];

const transformData = (data) => {
  let t = {};

  data.forEach((item, index, source) => {
    let l1 = item.LEVEL_1,
        l2 = item.LEVEL_2,
        l3 = item.LEVEL_3;
    t[l1]                         = t[l1]                         || {text: l1, content: {}, count: 0};
    t[l1].content[l2]             = t[l1].content[l2]             || {text: l2, content: {}, count: 0};
    t[l1].content[l2].content[l3] = t[l1].content[l2].content[l3] || {text: l3, content: {}, count: 0};
    t[l1].count++
    t[l1].content[l2].count++
    t[l1].content[l2].content[l3].count++
  })
  return t;
}

const transformDataTable = (tdata, sort = (a,b) => b-a, sort1 = sort, sort2 = sort1) => {

  const table = document.createElement('table');

  for (l1 of Object.keys(tdata).sort(sort)) {
    const td1 = document.createElement('th')
    td1.textContent = tdata[l1].text;
    td1.setAttribute('rowspan', tdata[l1].count)
    let done1 = false;

    for (l2 of Object.keys(tdata[l1].content).sort(sort1)) {
      const td2 = document.createElement('td')
      td2.textContent = tdata[l1].content[l2].text;
      td2.setAttribute('rowspan', tdata[l1].content[l2].count)
      let done2 = false;
      
      for (l3 of Object.keys(tdata[l1].content[l2].content).sort(sort2)) {
        const td3 = document.createElement('td')
        td3.textContent = tdata[l1].content[l2].content[l3].text;
        td3.setAttribute('rowspan', tdata[l1].content[l2].content[l3].count)
        const tr = document.createElement('tr')
        !done1 && tr.appendChild(td1) && (done1 = true);
        !done2 && tr.appendChild(td2) && (done2 = true);
        tr.appendChild(td3);
        table.appendChild(tr);
      }
    }
  }
  return table;
}

const asc = (a,b) => b-a
const desc = (a,b) => a-b

const tdata = transformData(data);
const table = transformDataTable(tdata, desc, asc);


document.body.appendChild(table)
table {
  border-collapse: collapse;
}

td,
th {
  padding: 20px;
  border: 1px solid black;
  text-align: center;
}

【讨论】:

    【解决方案2】:

    我将其分解为两个步骤: 1. 从输入数据生成树状结构以允许行跨度计数; 2. 绘制表格行列。

    整个代码尽可能通用以避免硬编码列数。

    我还添加了一个动态表格标题。如果您向数据结构添加另一列,HTML 表格标题也将得到更新。例如,可以使用相同的代码添加第四级,例如"LEVEL_4": "LEVEL 1.2.2.1" 一行或多行。

    var data = [
        {
            "LEVEL_1": "LEVEL 1",
            "LEVEL_2": "LEVEL 1.1",
            "LEVEL_3": "LEVEL 1.1.1"
        },
        {
            "LEVEL_1": "LEVEL 1",
            "LEVEL_2": "LEVEL 1.2",
            "LEVEL_3": "LEVEL 1.2.1"
        },
        {
            "LEVEL_1": "LEVEL 1",
            "LEVEL_2": "LEVEL 1.2",
            "LEVEL_3": "LEVEL 1.2.2"
        },
        {
            "LEVEL_1": "LEVEL 2",
            "LEVEL_2": "LEVEL 2.1",
            "LEVEL_3": "LEVEL 2.1.1"
        },
        {
            "LEVEL_1": "LEVEL 2",
            "LEVEL_2": "LEVEL 2.1",
            "LEVEL_3": "LEVEL 2.1.2"
        },
        {
            "LEVEL_1": "LEVEL 2",
            "LEVEL_2": "LEVEL 2.2",
            "LEVEL_3": "LEVEL 2.2.1"
        },
        {
            "LEVEL_1": "LEVEL 2",
            "LEVEL_2": "LEVEL 2.2",
            "LEVEL_3": "LEVEL 2.2.2"
        }
    ];
    
    /**
     * Generate rows and columns for the table using the JSON data.
     *
     * @param {Object} data
     * @param {HTMLTableSectionElement} tableBody
     * @param {HTMLTableSectionElement} tableHead
     */
    function setTableContent(data, tableBody, tableHead) {
        /* The rowspan is stored here depending on the label of each column */
        var columnRowspans = {};
    
        var columnHeadings = {};
    
        /**
         * Translate the data into a tree-like structure
         *
         * @param {JSON} data
         * @return {Array}
         */
        function translateData(data) {
            var rows = [];
            /* Iterate over each row in the dataset */
            data.forEach(function (row) {
                var columns = [],
                    label;
                /* Find the individual columns */
                for (var key in row) {
                    /* Store the columns header */
                    columnHeadings[key] = true;
    
                    label = row[key];
                    /* Skip those columns that were already added */
                    if (columnRowspans[label]) {
                        columnRowspans[label]++;
                        continue;
                    }
                    columns.push(label);
                    columnRowspans[label] = 1;
                }
                rows.push(columns);
            });
            return rows;
        }
    
        /* Template string used for a single field in the table */
        var cellTemplate = '<td rowspan="{rowspan}">{content}</td>';
    
        /* Output */
        var html = '';
        translateData(data).forEach(function (row, index) {
            html += '<tr>';
            row.forEach(function (columnLabel) {
                /* Use the stored rowspans here to generate columns */
                html += cellTemplate
                    .replace('{rowspan}', columnRowspans[columnLabel])
                    .replace('{content}', columnLabel);
            });
            html += '</tr>';
        });
    
        if (tableBody instanceof HTMLTableSectionElement) {
            tableBody.innerHTML = html;
        }
    
        if (tableHead instanceof HTMLTableSectionElement) {
            var thead = '<tr>';
            Object.keys(columnHeadings).forEach(function (heading) {
                thead += '<th>' + heading.replace('_', ' ') + '</th>';
            });
            thead += '</tr>';
            tableHead.innerHTML = thead;
        }
    }
    
    setTableContent(data, document.querySelector('#user tbody'), document.querySelector('#user thead'));
     table { 
          border-collapse: collapse;
        }
    
        td {
          padding: 20px; 
          border: 1px solid black; 
          text-align: center;
        }
    
        th {
          padding: 20px; 
          border: 1px solid black; 
          text-align: center;
        }
    <table id="user">
        <thead>
        </thead>
        <tbody> 
        </tbody>
    </table>

    【讨论】:

    • 我几乎发现这个答案是正确的。但是我运行了一些测试,并添加了新的 JSON 数据 {LEVEL_1 : "LEVEL 3", LEVEL_2 : "2.2","LEVEL_3" : "2.2.2"}和 LEVEL 3 中的 LEVEL 2.2,在 LEVEL 2 上合并到 LEVEL 2.2
    【解决方案3】:

    question 的帮助下,我设法合并了第一级。

    var data = [{
        "LEVEL_1": "LEVEL 1",
        "LEVEL_2": "LEVEL 1.1",
        "LEVEL_3": "LEVEL 1.1.1",
      },
      {
        "LEVEL_1": "LEVEL 1",
        "LEVEL_2": "LEVEL 1.2",
        "LEVEL_3": "LEVEL 1.2.1",
      },
      {
        "LEVEL_1": "LEVEL 1",
        "LEVEL_2": "LEVEL 1.2",
        "LEVEL_3": "LEVEL 1.2.2",
      },
      {
        "LEVEL_1": "LEVEL 2",
        "LEVEL_2": "LEVEL 2.1",
        "LEVEL_3": "LEVEL 2.1.1",
      },
      {
        "LEVEL_1": "LEVEL 2",
        "LEVEL_2": "LEVEL 2.1",
        "LEVEL_3": "LEVEL 2.1.2",
      },
      {
        "LEVEL_1": "LEVEL 2",
        "LEVEL_2": "LEVEL 2.2",
        "LEVEL_3": "LEVEL 2.2.1",
      },
      {
        "LEVEL_1": "LEVEL 2",
        "LEVEL_2": "LEVEL 2.2",
        "LEVEL_3": "LEVEL 2.2.2",
      }
    ];
    
    for (i = 0; i < data.length; i++) {
      var l1 = data[i].LEVEL_1;
      data[i].rowspan = 1;
      for (j = i + 1; j < data.length; j++) {
        var l2 = data[j].LEVEL_1;
        if (l1 == l2) {
          data[i].rowspan += 1;
        } else {
          break;
        }
      }
      i = j - 1;
    }
    var tableStr = '';
    $.each(data, function(index, value) {
      if (value.rowspan > 1) {
        tableStr += '<tr>' +
          '<td rowspan="' + value.rowspan + '">' + value.LEVEL_1 + '</td>' +
          '<td>' + value.LEVEL_2 + '</td>' +
          '<td>' + value.LEVEL_3 + '</td>' +
          '</tr>';
      } else {
        tableStr += '<tr>' +
          '<td>' + value.LEVEL_2 + '</td>' +
          '<td>' + value.LEVEL_3 + '</td>' +
          '</tr>';
      }
    
    
    });
    $('#user tbody').html(tableStr);
    table {
      border-collapse: collapse;
    }
    
    td {
      padding: 20px;
      border: 1px solid black;
      text-align: center;
    }
    
    th {
      padding: 20px;
      border: 1px solid black;
      text-align: center;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <table id="user">
      <thead>
        <tr>
          <th>LEVEL 1</th>
          <th>LEVEL 2</th>
          <th>LEVEL 3</th>
        </tr>
        <tr>
        </tr>
      </thead>
      <tbody>
      </tbody>
    </table>

    【讨论】:

      猜你喜欢
      • 2016-05-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-07
      • 2022-09-27
      • 2019-08-30
      • 1970-01-01
      • 2014-05-22
      相关资源
      最近更新 更多