0

really need your help. I'm trying to write a function that would generate HTML markup from javascript object.

My thoughts is I send an object and a root element as parameters and recursively append elements.

Here is the code.

const struct = [
  {
    tag: 'div',
    classes: ['container'],
    innerHtml: [
      {
        tag: 'input',
        classes: ['input'],
        attributes: [
          ['type', 'text'],
          ['placeholder', 'Some input']
        ]
      },
      {
        tag: 'div',
        classes: ['btn-block'],
        innerHtml: [
          {
            tag: 'div',
            classes: ['btn', 'btn-long'],
            innerText: 'Long Button'
          },
          {
            tag: 'div',
            classes: ['btn', 'btn-big', 'btn-img'],
            innerHtml: [
              {
                tag: 'img',
                attributes: [
                  ['src', 'https://www.w3schools.com/images/w3certified_logo_250.png']
                ],
              }
            ],
          }
        ]
      },
      {
        tag: 'div',
        classes: ['red']
      }
    ]
  }
];

const root = document.body;

function create(obj, root) {
  obj.forEach(o => {
    const element = document.createElement(o.tag);

    if (o.classes) {
      const classes = o.classes;
     element.classList.add(...classes);
    }
    if (o.attributes) {
      o.attributes.forEach(a => {
        element.setAttribute(a[0], a[1]);
      })
    }

    if (o.hasOwnProperty('innerHtml')) {
      element.append(create(o.innerHtml, element));
    }

    if (o.innerText) {
      element.innerText = o.innerText
    }

    root.append(element);
  });
}

create(struct, root);

And there is a result;

As you can see the function add text 'Undefined' to every element.

Could you help me to fix it?

UPD: Solved by answers from @CertainPerformance and @Nina Scholz

2 Answers 2

1

The problem is

element.append(create(o.innerHtml, element));

But create doesn't return anything, so undefined is appended to the end of every element. Change to just

create(o.innerHtml, element)

instead:

const struct = [{
  tag: 'div',
  classes: ['container'],
  innerHtml: [{
      tag: 'input',
      classes: ['input'],
      attributes: [
        ['type', 'text'],
        ['placeholder', 'Some input']
      ]
    },
    {
      tag: 'div',
      classes: ['btn-block'],
      innerHtml: [{
          tag: 'div',
          classes: ['btn', 'btn-long'],
          innerText: 'Long Button'
        },
        {
          tag: 'div',
          classes: ['btn', 'btn-big', 'btn-img'],
          innerHtml: [{
            tag: 'img',
            attributes: [
              ['src', 'https://www.w3schools.com/images/w3certified_logo_250.png']
            ],
          }]
        }
      ]
    },
    {
      tag: 'div',
      classes: ['red']
    }
  ]
}];

const root = document.body;

function create(obj, root) {
  obj.forEach(o => {
    const element = document.createElement(o.tag);

    if (o.classes) {
      const classes = o.classes;
      element.classList.add(...classes);
    }
    if (o.attributes) {
      o.attributes.forEach(a => {
        element.setAttribute(a[0], a[1]);
      })
    }

    if (o.hasOwnProperty('innerHtml')) {
      create(o.innerHtml, element)
    }

    if (o.innerText) {
      element.innerText = o.innerText
    }

    if (element !== undefined) {
      root.append(element);
    }
  });
}

create(struct, root);
.container {
  padding: 5px;
  border: 1px solid black;
  display: flex;
  justify-content: space-around;
  align-items: center;
}

.input {
  height: 20px;
  width: 200px;
}

.btn-block {
  display: flex;
  justify-content: space-around;
  align-items: center;
}

.btn {
  border: 1px solid black;
  border-radius: 5px;
  padding: 5px 15px;
  text-align: center;
}

.btn:hover {
  cursor: pointer;
}

.btn-long {
  width: 300px;
  margin-right: 10px;
}

.red {
  background: red;
  height: 100px;
  width: 100px;
}

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

Comments

1

You need only

create(o.innerHtml, element);

without wrapping element.append(/* ... */); because your function does not return somthing.

function create(obj, root) {
  obj.forEach(o => {
    const element = document.createElement(o.tag);

    if (o.classes) {
      const classes = o.classes;
      element.classList.add(...classes);
    }
    if (o.attributes) {
      o.attributes.forEach(a => {
        element.setAttribute(a[0], a[1]);
      })
    }

    if (o.hasOwnProperty('innerHtml')) {
       create(o.innerHtml, element);
      //element.append();
    }

    if (o.innerText) {
      element.innerText = o.innerText
    }

    root.append(element);
  });
}


const struct = [{
  tag: 'div',
  classes: ['container'],
  innerHtml: [{
      tag: 'input',
      classes: ['input'],
      attributes: [
        ['type', 'text'],
        ['placeholder', 'Some input']
      ]
    },
    {
      tag: 'div',
      classes: ['btn-block'],
      innerHtml: [{
          tag: 'div',
          classes: ['btn', 'btn-long'],
          innerText: 'Long Button'
        },
        {
          tag: 'div',
          classes: ['btn', 'btn-big', 'btn-img'],
          innerHtml: [{
            tag: 'img',
            attributes: [
              ['src', 'https://www.w3schools.com/images/w3certified_logo_250.png']
            ],
          }],
        }
      ]
    },
    {
      tag: 'div',
      classes: ['red']
    }
  ]
}];

const root = document.body;
create(struct, root);

Comments

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.