使用对象数组动态创建分组列表

时间:2016-11-25 20:23:16

标签: javascript jquery html

我有一个嵌套的对象数组,如下所示:

result = [
           [{"country":"France","continent":"Europe","name":"street a"}],
           [{"country":"Brazil","continent":"South America", "name":"street b"},{"country":"Brazil","continent":"South America", "name":"street c"}],
           [{"country":"Germany","continent":"Europe","name":"street d"}]
         ]

请注意,这是在排序后使用大陆然后使用国家/地区键从对象数组生成的。

我想动态生成如下列表(大陆,然后是国家/地区)并将其添加到div

  1. 欧洲
    • 法国
      • street a
    • 德国
      • street d
  2. 南美洲
    • 巴西
      • street b
      • street c
  3. 每次返回的国家和大陆都不同,但结果数组将按大陆,国家顺序分组。

    由于我不熟悉HTML,CSS和JavaScript,因此我无法弄清楚如何动态创建此列表。到目前为止,我已设法使用以下方法生成仅包含大陆的唯一列表:

    for(var i=0;i<result.length;i++){
        if($('#continent-list li').filter(function(){
             return $(this).text() == result[i][0].continent;
        }).length == 0){
             $('#continent-list').append('<li>'+result[i][0].continent+'<ul></ul></li>');
    }
    

    即,我遍历列表并且只是费心去查看第一个元素[result [i] [0])并将其添加到名为'continent-list'的无序列表中。每次我也检查名称是否已存在于无序列表中,如果不存在,则只有我添加。

6 个答案:

答案 0 :(得分:1)

我认为这样做的一种方法是遍历数组中的对象并为可用的大陆创建div,同时确保不会创建多个大陆,然后仍使用相同的循环,您可以使用类似

for(i=0;i<=results.length;i++){
  if (result[i].continent == continent) //here talking about the present continent in the main loop{
     //code to create new div for the current country....then same procedure for the street part....
    }
}

对不起,我听起来不太吵闹:D但是我希望你能得到范围

答案 1 :(得分:0)

var countries =[[{"country":"France","continent":"Europe","name":"street a"}], [{"country":"Brazil","continent":"South America", "name":"street b"}{"country":"Brazil","continent":"South America", "name":"street c"}], [{"country":"Germany","continent":"Europe","name":"street d"}]];

       var modified = {};

        for(var i =0; i<countries.length; i++){
          var continent = countries[i];
          for(var j =0;j<continent.length;j++){
              var country = continent[j];
              if(!modified[country.continent]){
                modified[country.continent] ={}
              }
               if(!modified[country.continent][country.country]){
                modified[country.continent][country.country] =[]
              }
              modified[country.continent][country.country].push(country);
         }
    }
    var liText = "<ul>";
    for (var key in modified) {
    liText += "<li>"+key + "<ul>";
    for (var country in  modified[key]){
      liText += "<li>"+country + "<ul>";
      for(var i=0;i< modified[key][country].length;i++){
        liText += "<li>"+modified[key][country][i].name + "</ll>";
      }
      liText += "</ul></li>";
    };
   liText += "</ul></li>";
      };
        liText += "</ul>"

console.log(liText);

document.getElementById('continent-list').innerHTML = liText;

答案 2 :(得分:0)

我会让你处理重复项,但这应该给你一般的想法:

jsFiddle

function displayData(continent, country, street) {
  console.log(continent + ', ' + country + ', ' + street);
  var output = $('#output');

  var continentLI = document.createElement('li');
  var continentTextNode = document.createTextNode(continent);

  continentLI.appendChild(continentTextNode);

  var countryUL = document.createElement('ul');
  var countryLI = document.createElement('li');
  var countryTextNode = document.createTextNode(country);
  countryLI.appendChild(countryTextNode);
  countryUL.appendChild(countryLI);

  var streetUL = document.createElement('ul');
  var streetLI = document.createElement('li');
  var streetTextNode = document.createTextNode(street);

  streetLI.appendChild(streetTextNode);
  streetUL.appendChild(streetLI);
  countryLI.appendChild(streetUL);

  continentLI.appendChild(countryUL);
  output.append(continentLI);
};

$.each(result, function(resultKey, resultValue) {
  var country = resultValue;
  $.each(country, function(countryKey, countryValue) {
    var continent = countryValue.continent;
    var country = countryValue.country;
    var street = countryValue.name;
    displayData(continent, country, street);
  });
});

答案 3 :(得分:0)

您可以展平数组,按属性WHERE table1.year_month IS NULLcontinentcountry排序,并在更改群组时构建所有新列表。

street
var result = [[{ "country": "France", "continent": "Europe", "name": "street a" }], [{ "country": "Brazil", "continent": "South America", "name": "street b" }, { "country": "Brazil", "continent": "South America", "name": "street c" }], [{ "country": "Germany", "continent": "Europe", "name": "street d" }]],
    flat = result.reduce(function (r, a) {
        return r.concat(a);
    }, []),
    ol = document.createElement('ol'),
    ul1, ul2;

flat.sort(function (a, b) {
    return a.continent.localeCompare(b.continent) || a.country.localeCompare(b.country) || a.name.localeCompare(b.name);
});

flat.forEach(function (a, i, aa) {
    var li;
    if (!i || aa[i - 1].continent !== a.continent) {
        li = document.createElement('li');
        li.appendChild(document.createTextNode(a.continent));
        ol.appendChild(li);
        ul1 = document.createElement('ul');
        ol.appendChild(ul1);
    }
    if (!i || aa[i - 1].country !== a.country) {
        li = document.createElement('li');
        li.appendChild(document.createTextNode(a.country));
        ul1.appendChild(li);
        ul2 = document.createElement('ul');
        ul1.appendChild(ul2);
    }
    li = document.createElement('li');
    li.appendChild(document.createTextNode(a.name));
    ul2.appendChild(li);
});

document.getElementById('out').appendChild(ol);

答案 4 :(得分:0)

我认为大部分工作都可以使用数组reduce函数来完成;)

第1步:我们会将您的数组转换为您需要的结构:

var result = [
    [{"country": "France", "continent": "Europe", "name": "street a"}],
    [{"country": "Brazil", "continent": "South America", "name": "street b"}, {
        "country": "Brazil",
        "continent": "South America",
        "name": "street c"
    }],
    [{"country": "Germany", "continent": "Europe", "name": "street d"}]
];

// fatten the arrays into single array
var continents = result.reduce(function (a, b) {
    return a.concat(b);
});

// group by continent
continents = continents.reduce(function (a, b) {
    if (a[b.continent]) {
        a[b.continent].push(b);
    } else {
        a[b.continent] = [b];
    }
    return a;
}, {});

// group by country
Object.keys(continents).forEach(function (continent) {
    continents[continent] = continents[continent].reduce(function (a, b) {
        if (a[b.country]) {
            a[b.country].push(b);
        } else {
            a[b.country] = [b];
        }
        return a;
    }, {});
});

现在这就是您的continents数据对象的样子:

{
  "Europe": {
    "France": [
      {
        "country": "France",
        "continent": "Europe",
        "name": "street a"
      }
    ],
    "Germany": [
      {
        "country": "Germany",
        "continent": "Europe",
        "name": "street d"
      }
    ]
  },
  "South America": {
    "Brazil": [
      {
        "country": "Brazil",
        "continent": "South America",
        "name": "street b"
      },
      {
        "country": "Brazil",
        "continent": "South America",
        "name": "street c"
      }
    ]
  }
}

第2步:我们将使用JQuery将此对象转换为html元素:

// create continents list
var $list = $('<ol id="continent-list"/>');
Object.keys(continents).forEach(function (continentName) {
    // create continent
    var $continent = $('<li class="continent"/>').append($("<span/>").text(continentName));

    // add countries
    var $countries = $('<ul class="country-list"/>');
    var continent = continents[continentName];
    Object.keys(continent).forEach(function (countryName) {
        var $country = $('<li/>').append($("<span/>").text(countryName));
        // add streets
        var $streets = $('<ul class="street-list"/>');
        var country = continent[countryName];
        country.forEach(function (street) {
            var $street = $('<li/>').text(street.name);
            $streets.append($street);
        });
        $country.append($streets);
        $countries.append($country);
    });
    $continent.append($countries);

    // add continent to the list
    $list.append($continent);
});

现在这就是$list的样子:

<ol id="continent-list">
    <li class="continent"><span>Europe</span>
        <ul class="country-list">
            <li><span>France</span>
                <ul class="street-list">
                    <li>street a</li>
                </ul>
            </li>
            <li><span>Germany</span>
                <ul class="street-list">
                    <li>street d</li>
                </ul>
            </li>
        </ul>
    </li>
    <li class="continent"><span>South America</span>
        <ul class="country-list">
            <li><span>Brazil</span>
                <ul class="street-list">
                    <li>street b</li>
                    <li>street c</li>
                </ul>
            </li>
        </ul>
    </li>
</ol>

第3步只需将其附加到文档中,例如:

$("body").append($list);

答案 5 :(得分:0)

This isn't the simplest requirement / request in the world, but it's not particularly convoluted, either. It bothers me that it takes so much code to solve. I know of no libraries that make this problem trivial, but two that come in very handy:

First, your records are excessively nested. To make them convenient to render, they should be flattened. Underscore can do this in one line:

var flat = _.flatten(result);

That isn't so hard in plain JS:

var flat = [];
result.forEach(sublist => {
  sublist.forEach(item => flat.push(item));
});

But it's nice to be able to "do it in one move" and move on.

Then you want several levels of nesting. Underscore has a nice groupBy feature, but it's single-level. There are other multi-level extensions out there, but that's more fussing around. D3, however, manages the nesting very easily:

var nested = d3.nest()
               .key(d => d.continent)
               .key(d => d.country)
               .entries(flat);

Then the nested data structure needs to be rendered to HTML. You can do that to HTML directly, but that's kind of messy. Thankfully, browsers have good tools for managing the DOM, aka their internal representation of HTML. D3 is great at manipulating it.

function nested2html(e, n, level) {
  level = level || 0;
  if (typeof e === 'string') e = d3.select(e);
  var list = e.append(level ? 'ul' : 'ol')
              .attr('class', 'level' + (level+1));
  var leafNode = !n[0].key;
  n.forEach(nitem => {
    if (leafNode) {
      list.append('li').text(nitem.name);
    } else {
      var li = list.append('li');
      li.append('span').text(nitem.key);
      nested2html(li, nitem.values, level + 1);
    }
  });
}

// now add it to the document
nested2html('body', nested);

This isn't particularly complicated as recursive routines go, and it renders out into well-structured, pretty easily styled HTML:

<ol class="level1">
  <li>
    <span>Europe</span>
    <ul class="level2">
      <li>
        <span>France</span>
        <ul class="level3">
          <li>street a</li>
        </ul>
      </li>
      <li>
        <span>Germany</span>
        <ul class="level3">
          <li>street d</li>
        </ul>
      </li>
    </ul>
  </li>
  <li>
    <span>South America</span>
    <ul class="level2">
      <li>
        <span>Brazil</span>
        <ul class="level3">
          <li>street b</li>
          <li>street c</li>
        </ul>
      </li>
    </ul>
  </li>
</ol>

A JSFiddle with the code running, and some optional CSS showing how the result can be styled.

I only wish there were a way to do this more concisely.