嵌套数组与平面表

时间:2016-05-27 09:59:42

标签: javascript jquery html datatables

我有嵌套对象,对象的深度可以是N,每个对象都可以有X属性以及嵌套到它的X对象。

问题

1)我无法猜测在整个循环完成之前将哪些列标题添加到我的表中。正如你在第一行中看到的那样,我只有一列“名称”,但在第二行中我有嵌套对象,这些对象为表添加了更多列标题。

2)我想使用jQuery数据表,它不适用于上述场景,因为所有行都没有相同数量的列

3)我不想硬编码任何东西,因为JSON数据可以是任何东西。

这是小提琴:https://jsfiddle.net/jwf347a4/8/

请注意,JSON是动态的,语法将保持不变,但对象和属性的数量+子对象的数量可能会有所不同,因此没有硬编码...谢谢

代码

var resultFromWebService = {
  //"odata.metadata": "http://localhost:21088/WcfDataService1.svc/$metadata#Categories&$select=Name,Products,Products/Currency/Symbol",
  "value": [{
    "Products": [],
    "Name": "Meat"
  }, {
    "Products": [{
      "Currency": {
        "ID": 47,
        "Num": 826,
        "Code": "GBP",
        "Description": "United Kingdom Pound",
        "DigitsAfterDecimal": 2,
        "Symbol": "\u00a3",
        "Hide": null,
        "Priority": 1
      },
      "ID": 2425,
      "Name": "303783",
      "ExpiryDate": "2014-02-22T00:00:00",
      "CurrencyID": 47,
      "Sales": "0.00000000000000000000",
      "PreTaxProfitOnProduct": null,
      "Assets": "0.30000000000000000000",
      "BarCode": null,
      "Worth": "0.20000000000000000000",
      "MarketValue": null
    }],
    "Name": "Produce & Vegetable"
  }]
};


var createBody = true;
var $table = $('<table id="myTable" class="defaultResultsFormatting"/>');
var $thead = $('<thead />');
var $tbody = $('<tbody />');
var $headRow = $('<tr/>');
var $parentCells = null;
var columnHeaders = [];
$table.append($thead);
var $resultContainer = createResultsTable(resultFromWebService);
$("#resultTableContainer").append($resultContainer);

//$('#myTable').dataTable();

function createResultsTable(data, title) {
  if (data) { // && data.length > 0) {
    if (createBody) {
      $thead.append($headRow);
      $table.append($tbody);
      createBody = false;
    }
    if (data.length > 0) {
      addColumnHeaders(data[0]);
      $.each(data, function(index, e) {
        populateTable(e);
      });
    } else {
      addColumnHeaders(data);
      populateTable(data);
    }
  } else {
    this.noResults();
  }

  function addColumnHeaders(result) {
    for (var property in result) {
      var type = typeof result[property];
      if (type === 'string' || type === 'number' || type === 'boolean' || result[property] instanceof Date || !result[property]) {
        var mainEntityName = result.__metadata ? result.__metadata.type.split(".").splice(-1)[0] + "." : "";
        mainEntityName = (title ? title + "." : mainEntityName);
        var cName = mainEntityName + property;
        if ($.inArray(cName, columnHeaders) < 0) {
          $headRow.append($('<th />', {
            text: cName
          }));
          columnHeaders.push(cName);
          console.log("columnHeader:" + cName);
        }
      }
    }
  }

  function populateTable(data) {
    var $bodyRow = null;
    if ($parentCells) {
      $bodyRow = $parentCells.clone();
    } else {
      $bodyRow = $('<tr/>');
    }

    var expandedChildResults = [];
    $.each(data, function(index, property) {
      var type = typeof property;
      if (type === 'string' || type === 'number' || type === 'boolean') {
        $bodyRow.append($('<td />', {
          text: property
        }));
      } else if (property instanceof Date) { // DataJS returns the dates as objects and not as strings.
        $bodyRow.append($('<td />', {
          text: property.toDateString()
        }));
      } else if (!property) {
        $bodyRow.append('<td />');
      } else if (typeof property === 'object' && property.results && index !== '__metadata') {
        expandedChildResults.push({
          key: property.results,
          value: index
        });
      } else if (typeof property === 'object' && index !== '__metadata' && index !== '__deferred' && !isPropertyAnObjectWithJustSingle__deferred(property)) {
        expandedChildResults.push({
          key: property,
          value: index
        });
      }
    });

    if (expandedChildResults.length > 0) {
      $.each(expandedChildResults, function(index, childObject) {
        $parentCells = $bodyRow;
        createResultsTable(childObject.key, childObject.value);
      });
      $parentCells = null;
    } else
      $tbody.append($bodyRow);
      console.log($bodyRow);
  }

  function isPropertyAnObjectWithJustSingle__deferred(property) {
    var keys;
    return typeof property === 'object' && // test if it's and object
      (keys = Object.keys(property)).length === 1 && // test if it has just sibgle property
      keys[0] === '__deferred'; // test if that property is '__deferred'
  }

  return $table;
};

最大问题/摘要

我遇到的问题是,我不确定在构建整个表对象后如何向行添加空单元格,否则jQuery datable将不喜欢它。

更新

当我有超过1个嵌套的子数组时,当前的答案不起作用等等......

https://jsfiddle.net/1tsu6xt9/46/

正如你所看到的只有一排,我希望它能显示3,就像我在这个小提琴中一样,

https://jsfiddle.net/jwf347a4/24/

2 个答案:

答案 0 :(得分:2)

我建议跟踪哪些列已经存在,并使用它来检测何时需要注入新列或跳过未使用的列。

Live Demo

foreach x in ///
"GREEN BLUE" ///
"RED ORANGE" ///
{
replace y = 1 if COLOUR == "`x'" & missing(y)
} 

如何运作

首先,它会使记录变平,以摆脱嵌套。

然后,对于每列,查看该列是否已存在。

如果该列存在,请查看我们是否正在跳过列。如果是这样,我们跳过那么多并插入那么多空单元格。如果没有,我们会记住我们在哪一行,因此我们可以在适当的索引处插入所有先前行中的单元格。

答案 1 :(得分:1)

解决方案 Working Fiddle )构建完表后,调用另一个函数来完成表格将缺少的单元格添加到行中

这种逻辑必须有所帮助。

function RestructureTheDynamicTable(){
 var $table = $('#myTable');
 var maxColumns = $table.find('thead tr th').length;    //find the total columns required

  $table.find('tbody tr').each(function(){
    var thisRowColumnCount = $(this).find('td').length;
    var extraTds = "";
    if(maxColumns > thisRowColumnCount){    //if this row doesn't have the required number of columns lets add them
      for(var i=0;i < maxColumns - thisRowColumnCount;i++){
        extraTds += "<td></td>";
      }
      $(this).append(extraTds);
    }    
  });
}

完成构建表格后调用此函数。表完成重组后,您可以应用Datatables插件