2

How to parse js array in the form similar to:

const arr = [
            "&&",
            [
                "==",
                "first",
                "1-1"
            ],
            [
                "&&",
                [
                    "==",
                    "second1",
                    "2-1"
                ],
                [
                    "==",
                    "second2",
                    "2-2"
                ]
            ]
        ]

to HTML unordered (ul) list in the form:

<ul>
    <li>&&
        <ul>
            <li>first == 1-1</li>
            <li>&&
                <ul>
                    <li>second1 == 2-1</li>
                    <li>second2 == 2-2</li>
                </ul>
            </li>
        </ul>
    </li>
</ul>

Arr is allways in form [operator, conditions/subdonctions]. As you can guess, I need an UI to edit arr content. Arr represents form of 'where' filter definition in JSON string. So when user changes list (adding or removing nodes in unordered list)i will need to parse changes back to array, but first things first. Maybe there is some library for that but i was unable to find it.

I tried recursion like this:

    function arrayToHTML(arr, container) {
     if (!Array.isArray(arr) || arr.length === 0) return
     const operator = arr[0]
     const conditions = arr.slice(1)
     if (operator === '&&') {
      this.arrayToHTML(conditions, container)
     }
    }
4
  • How does your function not meet your expectations? When/how do you call your function? Commented Dec 27, 2023 at 13:56
  • What are the rules for your structure? Is it always [operator, conditions/subconditions]? Commented Dec 27, 2023 at 14:18
  • Yes arr rule is [operator, conditions/subdonctions] and minimal there is one condition and max there are two. Commented Dec 27, 2023 at 14:23
  • No stackoverflow.com/questions/21140069/… is different, look at arr structure (no JSON data) Commented Dec 27, 2023 at 14:25

1 Answer 1

3

One possible option is to separate out the first operator element of your array (op) from the remainder of the array (conds) (done using argument destructuring) and then build your <li> using the operator element, with nested children below, that's built based on mapping the conds array. Before you map the conds array though, you can first check if the first element in conds is an array (if it's an arary, it suggests it has nested/sub conditions). If it is an array, you can recursively build your list structure again. Otherwise, if the first element in conds isn't an array, then you've hit your base case and can build the child/terminating <li> condition string:

const arr = ["&&", [ "==", "first", "1-1" ], [ "&&", [ "==", "second1", "2-1" ], [ "==", "second2", "2-2" ] ] ];

const generateHTMLAux = ([op, ...conds]) => {
  const [second, third] = conds;

  return Array.isArray(second)
    ? `<li>${op}
      <ul>
        ${conds.map(generateHTMLAux).join('')}
      </ul>
    </li>`
    : `<li>${second} ${op} ${third}</li>`;
}
const generateHTML = (arr) => `<ul>${generateHTMLAux(arr)}</ul>`;

const res = generateHTML(arr);
document.body.innerHTML = res;
console.log(res);
See browser console for HTML structure

Sign up to request clarification or add additional context in comments.

4 Comments

Kudos ! Just what I need.
Just one more hint, please: arr can degrade to just const arr = [ "==", "first", "1-1"], and code breaks in this case...
@AlenKelemen Hi, I've updated my answer, I've moved the logic that handles checking the second element outside of the .map() and into the body of the function.
I think you could make a treview control out of your excellent answer (with nested arr as input/output) as a small library at github or similar...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.