0

I have a function I am using to take a generated nested array and turn it into nested ULs:

const prepareUL = (root, arr) => {
   let ul = document.createElement('ul');
  
   root.appendChild(ul);
   arr.forEach(function(item) {
      let li = document.createElement('li');
      if (Array.isArray(item)) {
         prepareUL(li, item);
         ul.appendChild(li);
         return
      };
      li.appendChild(document.createTextNode(item));
      ul.appendChild(li);
   });
   
}

The generated array looks like:

[
   [
    "text-ID1",
    "Section Title 1",
    "Section paragraph 1",
    "Section Paragraph 2"
    ],
    [
    "text-ID2",
    "Section Title 2",
    "Section paragraph 1",
    "Section Paragraph 2"
    ],
    [
    "text-ID3",
    "Section Title 3",
    "Section paragraph 1",
    "Section Paragraph 2"
    ]
]

I need to get the second element from array and extract it and prepend it to the UL it belongs to as a div. So generated structure would look like:

<ul>
    <div>Section Title 1</div>
    <ul>
        <li>Section paragraph 1</li>
        <li>Section paragraph 2</li>
    </ul>
    <div>Section Title 3</div>
    <ul>
        <li>Section paragraph 1</li>
        <li>Section paragraph 2</li>
    </ul>
    <div>Section Title 3</div>
    <ul>
        <li>Section paragraph 1</li>
        <li>Section paragraph 2</li>
    </ul>
</ul>

My untrained instinct is to use DOM manipulation after the fact, because I know how to do that, but it seems inelegant and like I should be able to do that here. Too new to understand it well enough.

chris
  • 1,172
  • 12
  • 15
  • I suppose it's not good to have div, ul to be children of ul. more info here.. https://stackoverflow.com/a/11755657/6310485 – harpal Sep 23 '22 at 15:08
  • @harpal Appreciated. I have fixed the output of the code to use legal HTML. – chris Sep 23 '22 at 17:55

3 Answers3

1

To simplify the control about the Array of Arrays (Matrix) I suggest to use for loop, using the for loop, this could be a solution:

const arr = [
    [
    "text-ID1",
    "Section Title 1",
    "Section paragraph 1",
    "Section Paragraph 2"
    ],
    [
    "text-ID2",
    "Section Title 2",
    "Section paragraph 1",
    "Section Paragraph 2"
    ],
    [
    "text-ID3",
    "Section Title 3",
    "Section paragraph 1",
    "Section Paragraph 2"
    ]
]

const prepareUL = (root, arr) => {
   let ul = document.createElement('ul');
  
   root.appendChild(ul);
    
   for (let i=0; i<arr.length; i++) {
     for (let j=0; j<arr[i].length; j++) {
       if (j==0) { continue; }       
       const item = arr[i][j];
       
       if (j==1) {
          let div = document.createElement('div');
          div.appendChild(document.createTextNode(item));
          ul.appendChild(div);
       }else{
          let ul2 = document.createElement('ul');
          let li = document.createElement('li');
         
          if (Array.isArray(item)) {
            prepareUL(li, item);         
            ul.appendChild(li);
            return;
          }       
          li.appendChild(document.createTextNode(item));
          ul2.appendChild(li);
         
          ul.appendChild(ul2);
       }       
     }
   }
   
}

prepareUL(document.getElementById('root'), arr)
<div id="root"></div>
ricxk
  • 67
  • 1
  • 10
  • Sorry for the haste, but this doesn't quite generate the right HTML, although it appears to. It actually generates a new UL for every nested LI. – chris Sep 23 '22 at 15:17
1

This should help you

Update:-

        var arr = [
            [
                "text-ID1",
                "Section Title 1",
                "Section paragraph 1",
                "Section Paragraph 2"
            ],
            [
                "text-ID2",
                "Section Title 2",
                "Section paragraph 1",
                "Section Paragraph 2"
            ],
            [
                "text-ID3",
                "Section Title 3",
                "Section paragraph 1",
                "Section Paragraph 2"
            ]
        ];
        const prepareUL = (root, arr) => {
            let main = document.createElement('ul');
            let root2 = document.getElementById(root)

            arr.forEach(function (item) {

                let title_div = document.createElement('div');
                title_div.innerHTML = item[1];

                let item_ul = document.createElement('ul');
                for (var i = 2; i < item.length; i++) {
                    let item_li = document.createElement('li');
                    item_li.innerHTML = item[i];
                    item_ul.append(item_li);
                }
                main.appendChild(title_div);
                main.appendChild(item_ul);

            });
            root2.appendChild(main)
        }

        prepareUL("root", arr);
 <id id="root"></id>
Mohamed EL-Gendy
  • 566
  • 4
  • 11
0

If you don't mind to use a tiny library, then the solution can be simplified greatly to this:

<script type="module">
import { insert } from '//cdn.jsdelivr.net/npm/karyon/karyon.js';

const arr = [
   [
    "text-ID1",
    "Section Title 1",
    "Section paragraph 1",
    "Section Paragraph 2"
    ],
    [
    "text-ID2",
    "Section Title 2",
    "Section paragraph 1",
    "Section Paragraph 2"
    ],
    [
    "text-ID3",
    "Section Title 3",
    "Section paragraph 1",
    "Section Paragraph 2"
    ]
];

const out = {is: 'ul', content: arr.map(([id, title, ...sections]) => [
  {content: title},
  {is: 'ul', content: sections.map(li => ({is: 'li', content: li}))}
])}

insert(out, document.body);
</script>
n--
  • 3,563
  • 4
  • 9