最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

html - JavaScript: How to create unordered list from array? - Stack Overflow

programmeradmin3浏览0评论

I have the following array and I want to create an unordered list from it, but I am having trouble generating the unordered list in the proper format. I have searched similar questions but none of the existing solutions work for my problem.

var myArray = ['Value 1', ['Inner value 1', 'Inner value 2', 'Inner value 3', 'Inner value 4'], 'Value 2', 'Value 3', 'Value 4', 'Value 5', 'Value 6'];

Here is my JavaScript code:

function arrToUl(arr) {
  var div = document.getElementById('myList');
  var ul = document.createElement('ul');

  for (var i = 0; i < arr.length; i++) {

    if (arr[i] instanceof Array) {
      var list = arrToUl(arr[i]);
    } else {
      var li = document.createElement('li');
      li.appendChild(document.createTextNode(arr[i]));
      console.log(ul.appendChild(li));
    }
    div.appendChild(ul);
  }
}

arrToUl(myArray);

The above code is producing the following result:

<ul>
<li>Value 1</li>
<li>Inner Value 1</li>
<li>Inner Value 2</li>
<li>Inner Value 3</li>
<li>Inner Value 4</li>
<li>Value 2</li>
<li>Value 3</li>
<li>Value 4</li >
<li>Value 5</li >
<li>Value 6</li>

But the result should look like below:

<ul>
<li>Value 1
    <ul>
        <li>Inner Value 1</li>
        <li>Inner Value 2</li>
        <li>Inner Value 3</li>
        <li>Inner Value 4</li>
    </ul>
</li>
<li>Value 2</li>
<li>Value 3</li>
<li>Value 4</li>
<li>Value 5</li>
<li>Value 6</li>

Thank you for your help.

I have the following array and I want to create an unordered list from it, but I am having trouble generating the unordered list in the proper format. I have searched similar questions but none of the existing solutions work for my problem.

var myArray = ['Value 1', ['Inner value 1', 'Inner value 2', 'Inner value 3', 'Inner value 4'], 'Value 2', 'Value 3', 'Value 4', 'Value 5', 'Value 6'];

Here is my JavaScript code:

function arrToUl(arr) {
  var div = document.getElementById('myList');
  var ul = document.createElement('ul');

  for (var i = 0; i < arr.length; i++) {

    if (arr[i] instanceof Array) {
      var list = arrToUl(arr[i]);
    } else {
      var li = document.createElement('li');
      li.appendChild(document.createTextNode(arr[i]));
      console.log(ul.appendChild(li));
    }
    div.appendChild(ul);
  }
}

arrToUl(myArray);

The above code is producing the following result:

<ul>
<li>Value 1</li>
<li>Inner Value 1</li>
<li>Inner Value 2</li>
<li>Inner Value 3</li>
<li>Inner Value 4</li>
<li>Value 2</li>
<li>Value 3</li>
<li>Value 4</li >
<li>Value 5</li >
<li>Value 6</li>

But the result should look like below:

<ul>
<li>Value 1
    <ul>
        <li>Inner Value 1</li>
        <li>Inner Value 2</li>
        <li>Inner Value 3</li>
        <li>Inner Value 4</li>
    </ul>
</li>
<li>Value 2</li>
<li>Value 3</li>
<li>Value 4</li>
<li>Value 5</li>
<li>Value 6</li>

Thank you for your help.

Share Improve this question edited Dec 27, 2016 at 22:18 guest271314 1 asked Dec 27, 2016 at 22:13 EBambaEBamba 1451 gold badge2 silver badges10 bronze badges 2
  • Q: What should the result be if myArray = ['Value 1', ['Inner value 1', 'Inner value 2', 'Inner value 3', 'Inner value 4'], ['Inner value 5', 'Inner value 6', 'Inner value 7', 'Inner value 8'], 'Value 2', 'Value 3', 'Value 4', 'Value 5', 'Value 6'] ? – Khalid T. Commented Dec 27, 2016 at 22:26
  • Using instanceof to detect an Array is unreliable, use Array.isArray instead. – RobG Commented Dec 27, 2016 at 22:55
Add a comment  | 

6 Answers 6

Reset to default 9

You've appended all the <ul> elements to the myList <div>. To change that, I've added a new parameter to the arrToUl(root, arr) function.

The new parameter, root, determines who the created <ul> should be appended to, so if the function encounters a sub-array, it uses the previous list item as the root for the creation of the sub-list.

var myArray = ['Value 1', ['Inner value 1', 'Inner value 2', 'Inner value 3', 'Inner value 4'], 'Value 2', 'Value 3', 'Value 4', 'Value 5', 'Value 6'];

function arrToUl(root, arr) {
  var ul = document.createElement('ul');
  var li;
  
  root.appendChild(ul); // append the created ul to the root

  arr.forEach(function(item) {
    if (Array.isArray(item)) { // if it's an array
      arrToUl(li, item); // call arrToUl with the li as the root
      return;
    }
    
    li = document.createElement('li'); // create a new list item
    li.appendChild(document.createTextNode(item)); // append the text to the li
    ul.appendChild(li); // append the list item to the ul
  });
}

var div = document.getElementById('myList');

arrToUl(div, myArray);
<div id="myList"></div>

Your function is called arrToUl, so it should just do that: convert the array to an ul.

Once you have the ul you can insert it wherever you want, but take that outside the function.

Then it all becomes clear.

function arrToUl(arr) {
  var ul = document.createElement('ul'), li;
  for (var i = 0; i < arr.length; i++) {
    if (Array.isArray(arr[i])) {
      li.appendChild(arrToUl(arr[i]));
    } else {
      li = document.createElement('li');
      li.appendChild(document.createTextNode(arr[i]));
      ul.appendChild(li);
    }
  }
  return ul;
}
var myArray = ['Value 1', ['Inner value 1', 'Inner value 2', 'Inner value 3', 'Inner value 4'], 'Value 2', 'Value 3', 'Value 4', 'Value 5', 'Value 6'];
document.body.appendChild(arrToUl(myArray));

With vanilla JS (using ES6 syntax):

const myArray = [
  "Value 1",
  ["Inner value 1", "Inner value 2", "Inner value 3", "Inner value 4"],
  "Value 2",
  "Value 3",
  "Value 4",
  "Value 5",
  "Value 6",
];

const arrayToUL = (arr) => {
  const ul = document.createElement("ul");
  ul.append(
    ...arr.map((value) => {
      if (Array.isArray(value)) return arrayToUL(value);
      const li = document.createElement("li");
      li.textContent = value;
      return li;
    })
  );
  return ul;
};

document.body.appendChild(arrayToUL(myArray));

In ReactJS (takes an array as its children):

const List = ({ children }) => (
  <ul>
    {children.map((val) =>
      Array.isArray(val) ? List({ children: val }) : <li>{val}</li>
    )}
  </ul>
);

const myArray = [
  "Value 1",
  ["Inner value 1", "Inner value 2", "Inner value 3", "Inner value 4"],
  "Value 2",
  "Value 3",
  "Value 4",
  "Value 5",
  "Value 6",
];

const App = () => <List>{myArray}</List>;

ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>

Your recursive approach doesn't say anything about where it should append the new child. Maybe you should give, every time you get an instance of an array, the last element an unique id. And then you could give this id with your function paramers.

GUID Generator is a good way to make an unique id.

I would propose a solution based on recursion, it seems to me clearer and less error-prone. It produces a slightly different result as it maps each array element to a node at the same level and I think this should be the output of creating a ul from an array.

var myArray = [
  'Value 1',
  ['Inner value 1', 'Inner value 2', 'Inner value 3', 'Inner value 4'],
  'Value 2',
  'Value 3',
  'Value 4',
  'Value 5',
  'Value 6'
];

function appendItems(arr, el) {
  if(!arr.length) return el;
  else {
      var head = arr.shift();
      var child = transform(head);
      var li = document.createElement('li');
      li.appendChild(child);
      el.appendChild(li);
      return appendItems(arr, el);
  }
}

function transform(item) {
  if(Array.isArray(item)) {
    var ul = document.createElement('ul');
    return appendItems(item, ul);
  } else {
    return document.createTextNode(item);
  }
}

var ul = transform(myArray);

If you would like to have the output you mentioned, it could be better to change the input format in order to match one iteration per node. Ex:

var arr = [
  {label: 'value1', subitems: ['Inner value 1', 'Inner value 2', 'Inner value 3', 'Inner value 4']}
];

You could save the last li and append to it with an extended function with a target DOM element.

function iter(target) {
    var ul = document.createElement('ul'),
        li;

    target.appendChild(ul);
    return function (a) {
        if (Array.isArray(a)) {
            if (!li) {
                li = document.createElement('li');
                ul.appendChild(li);
            }
            a.forEach(iter(li));
            return;
        }
        li = document.createElement('li');
        li.appendChild(document.createTextNode(a));
        ul.appendChild(li);
    };
}

var myArray = ['Value 1', ['Inner value 1', 'Inner value 2', 'Inner value 3', 'Inner value 4'], 'Value 2', 'Value 3', 'Value 4', 'Value 5', 'Value 6'];

myArray.forEach(iter(document.getElementById('myList')));
<div id="myList"></div>

发布评论

评论列表(0)

  1. 暂无评论