Vladimir Lebedev
Vladimir Lebedev

Reputation: 115

Convert object to HTML element

In input of function is an object who has this structure:

{
  tag: 'a', //type of html object
  content: "blabal", //inner content
  attr: {
    href: "vk.com",
    id: 'someId'
  },
  events: {
    click: 'alert(this.href)',
    focus: 'this.className="active"'
  },
  style: {
    width:"100px"
  }
}

It describes an HTML element. It has to return an HTML element with specified properties. How to parse it? I have something like this:

elemen={
  tag:'a',
  content:"blabal",
  attr:{
    href:"vk.com",
    id:'someId'
  },
  events:{
   click:'alert(this.href)',
   focus:'this.className="active"'
  },
  style:{
    width:"100px"
  }
};
console.log(elemen.tag);
var node = document.createElement(elemen.tag);
node.innerHTML= elemen.content;

for(var prop in elemen.events){

  var fun =new Function(elemen.events[prop]);
  console.log(fun);
  node.bind(prop, fun);
//   divv.bind(prop, fun);
}

Upvotes: 8

Views: 33266

Answers (4)

Michał Perłakowski
Michał Perłakowski

Reputation: 92501

Use the following function:

const objectToHTML = function(obj) {
  const element = document.createElement(obj.tag)
  element.innerHTML = obj.content
  for (const name in obj.attr) {
    const value = obj.attr[name]
    element.setAttribute(name, value)
  }
  for (const name in obj.events) {
    const listener = new Function(obj.events[name]).bind(element)
    element.addEventListener(name, listener)
  }
  for (const property in obj.style) {
    const value = obj.style[property]
    element.style[property] = value
  }
  return element
}

To create an event listener from string, you have to convert it to function using the Function constructor, bind context to it using Function.prototype.bind() (otherwise the function would be executed with window as context), and finally, use element.addEventListener().

The rest is rather obvious.

You can use this function like that:

const element = objectToHTML({
  tag: 'a',
  content: "blabal",
  attr: {
    href: "vk.com",
    id: 'someId'
  },
  events: {
    click: 'alert(this.href)',
    focus: 'this.className="active"'
  },
  style: {
    width: "100px"
  }
})

document.body.appendChild(element)

See demo:

const objectToHTML = function(obj) {
  const element = document.createElement(obj.tag)
  element.innerHTML = obj.content
  for (const name in obj.attr) {
    const value = obj.attr[name]
    element.setAttribute(name, value)
  }
  for (const name in obj.events) {
    const listener = new Function(obj.events[name]).bind(element)
    element.addEventListener(name, listener)
  }
  for (const property in obj.style) {
    const value = obj.style[property]
    element.style[property] = value
  }
  return element
}

const element = objectToHTML({
  tag: 'a',
  content: "blabal",
  attr: {
    href: "vk.com",
    id: 'someId'
  },
  events: {
    click: 'alert(this.href)',
    focus: 'this.className="active"'
  },
  style: {
    width: "100px"
  }
})

document.body.appendChild(element)

Upvotes: 0

I recommend this form, is more adaptable.

window.onload = function() {
 
  function init_() {

    function action__(type, element, convert, a) {
      if (type == "function") {
        if (convert.create[a] != null) {
          try {
            var new_ = convert.create[a](element[a]);
          } catch (rrr) {
            rrr = (rrr.toString());

            if (rrr.indexOf('2 arguments') != -1 && Object.keys(element[a]).length != 0) {
              for (v in element[a]) {
                convert.create[v] = element[a][v];
                var new_ = convert.create;
              }
            };
          }
          convert['create'] = new_;
        }

      };

      if (type == "object") {
        for (f in element[a]) {
          convert.create[a][f] = element[a][f];
        }
      }

      if (type == "string" && a != "events") {
        convert.create[a] = (element[a]);
      } else if (type == "string" && a == "events") {
        for (ev in element[a]) {
          var type = convert.detectType(convert.create, ev);
          if (type == "function") {
            convert.create.addEventListener(ev, new Function(element[a][ev]));
          }
        };
      };



      return convert.create;
    };


    function createElement(elements) {

      var finished = [];

      if (typeof elements.tagName == "undefined" && !elements.length) {
        elements = [elements];
      }

      for (r = 0; r < elements.length; r++) {
        var element = elements[r];
        if (element) {
          var convert = {
            create: document,
            detectType: function(element, attribute) {
              var type = "string";
              if (typeof element[attribute] != "undefined") {
                type = typeof element[attribute];
              };
              return type;
            },
            add: function(new_) {
              if (new_ && new_ != "undefined") {
                this.create = new_;
              }
            }

          };

          for (a in element) {

            var type = convert.detectType(convert.create, a);
            var returner = action__(type, element, convert, a);
            convert.add(returner);
          }


          finished.push(convert.create);
        };

      }
      return (finished);

    };

    var minifi_function = init_.toString();
    
    var elements = [{
      createElement: 'a', 
      innerHTML: "blabal", 
      setAttribute: {
        href: "vk.com",
        id: 'someId',
        style: "height:200px;"
      },
      events: {
        click: 'alert(this.href)',
        focus: 'this.className="active"'
      },
      style: {
        width: "100px"
      }
    }, {
      createElement: 'div', 
      innerHTML: "see my content", 
      setAttribute: {
        ['data-link']: "vk.com",
        id: 'someId2',
        style: "height:200px;background:red;"
      },
      events: {
        click: 'prompt("Copy",' + minifi_function + ')',
        focus: 'this.className="activediv"'
      },
      style: {
        width: "100px"
      }
    }];



    var elementos = createElement(elements);
    console.log(elementos);
    for (p = 0; p < elementos.length; p++) {
      document.body.appendChild(elementos[p]);
    }

  }

  init_();
}

Upvotes: -1

brk
brk

Reputation: 50291

Using only javascript

 var _createElem = document.createElement(""+_elem.tag+""); 
 _createElem.innerHTML = _elem.content;

//set attributes
for(var keys in _elem.attr){
  _createElem.setAttribute(''+keys+'',_elem.attr[keys])
 }
//set style 
 for(var keys in _elem.style){
  _createElem.setAttribute(''+keys+'',_elem.style[keys])
 }
//set events
for(var keys in _elem.events){
_createElem.setAttribute('on'+keys,_elem.events[keys])
} 
document.getElementById("demoDiv").appendChild(_createElem)

Note: The elem has got both onclick & href , you may need to return true/false as per your requirement

Upvotes: 4

Rayon
Rayon

Reputation: 36609

Use addEventListener to register events on Element and .bind(thisArg) to have specified argument as this-context

var elemen = {
  tag: 'a',
  content: "blabal",
  attr: {
    href: "vk.com",
    id: 'someId'
  },
  events: {
    click: 'alert(this.href)',
    focus: 'this.className="active"'
  }
};
var node = document.createElement(elemen.tag);
node.innerHTML = elemen.content;
for (var attr in elemen.attr) {
  node.setAttribute(attr, elemen.attr[attr]);
}
for (var prop in elemen.events) {
  node.addEventListener(prop, new Function(elemen.events[prop]).bind(node));
}
document.body.appendChild(node);
.active {
  color: red;
}

Upvotes: 7

Related Questions