1

I have this code:

/* Creating whole HTML Units from HTML Element list */
function createHTMLUnit(unitstruct){
  var tempElement;
  Object.entries(unitstruct).forEach(([key, value]) => {
    // First of all we start a loop
    if(typeof value==='object'&&key==='$child'){ //Find out that we have an Object and it's a child
      //If yes we append this as a child to the tempElement with call this function again
      tempElement.appendChild(createHTMLUnit(value));
    }else{
      //If not we reach a single element have to find out what we should do with it
      //Switch from the cases like '$tag', '$attr', '$child' or other (will be a value)
      switch(key){
        case '$tag': //Createing the element in value
            tempElement = document.createElement(value);
          break;
        case '$attr': //Loop through the value and set attributes for the element
            Object.entries(value).forEach(([attrkey, attrvalue]) => {
              tempElement.setAttribute(attrkey, attrvalue);
            })
          break;
        case '$child': //Element innerHTML
            return tempElement;
          break;
        default:  //Return with the value to the previous loop
            return tempElement;
        break;
      }
    }
  });
  
  var htmlUnitParam = {
      '$tag': 'div',
      '$attr': {
        'class':'msg-box',
        'id':'msg-box01'
      },
      '$child': {
        '$tag': 'div',
        '$attr': {
          'class':'msg-box-container',
          'id':'msg-box-container01'
        },
        '$child': ''
      }
    }

    document.body.appendChild(createHTMLUnit(htmlUnitParam));

If I run this it will be drop an "Uncaught TypeError: Failed to execute 'appendChild' on 'Node': parameter 1 is not of type 'Node'." error. If I take things apart like:

var x = createHTMLUnit(value);
tempElement.appendChild(x);

'x' gonna be undefined after createHTMLUnit returns (as I checked in Chrome Inspector, at the point'return tempElement;' tempElement hold it's value and the function return undefined...) so appendChild can't apply anything to the node.

Anybody have any idea what is the problem? And how can I fix it? (And yes, I should use recrusion and a function like this one...)

Progman
  • 16,827
  • 6
  • 33
  • 48
bradacsa
  • 19
  • 3
  • Not all paths are returning something, that's why. Some paths return `undefined` – Terry Feb 27 '22 at 22:22
  • `createHTMLUnit` doesn't return anything at all. Take a closer look at your code and consider which function actually contains your `return` statements. Answer: it's the callback function that you pass to the `forEach` method, NOT `createHTLUnit`. – Lennholm Feb 27 '22 at 22:32

2 Answers2

0

You are trying to return a value from the function, but your return statements are inside a forEach loop callback function. Returning inside the loop doesn't return from the outer function, so at the end of the loop it just returns nothing.

Related info on forEach return

That link contains some other alternatives, but basically you want to replace the forEach loop with a regular for loop, going through the Object.keys or Object.values and then your returns should start to function as you originally expected.

msenne
  • 613
  • 5
  • 8
0

Thanks for everybody!

Meanwhile I just find an other way (maybe it's a bit comfortable as well) to get it to work.

function createHTMLUnit(unitstruct, appendto){
  var tempElement;
  Object.entries(unitstruct).forEach(([key, value]) => {
    if(typeof value==='object'&&key==='$child'){
      createHTMLUnit(value, tempElement);
    }else{
      switch(key){
        case '$tag':
            tempElement = document.createElement(value);
          break;
        case '$attr':
            Object.entries(value).forEach(([attrkey, attrvalue]) => {
              tempElement.setAttribute(attrkey, attrvalue);
            })
          break;
        case '$child':
            tempElement.innerHTML = value;
            return;
          break;
        default:
            createHTMLUnit(value, appendto);
          break;
      }
    }
  });
  if(tempElement!=undefined){ 
    appendto.appendChild(tempElement);
  }
}

Maybe it's not that nice but it works fine.

bradacsa
  • 19
  • 3