Question

Background

I'm trying to make a completely pure JavaScript GUI for creating HTML content for learning purposes. The only real html in the file will be one <script></script> element. I'm almost finished, I think.

I made a custom HTML element constructor, but when I create an object, [object Object] is displayed instead of [object HTMLWhateverElement] when I do alert(whatever); (see the example below). I think that's preventing me from appending child elements to parent elements when both are made by the constructor.

The main problem

If I could get HTML instances to append to HTML tags and element instances, then I would be very happy.

Constructor

function element(tagName) {
    var element = document.createElement(tagName);

    this.setText = function(elementText) {
        if(element.childNodes.length < 1) {
            var text = document.createTextNode(elementText);
            element.appendChild(text);
        } else {
            element.childNodes[0].nodeValue = elementText;
        }
    }

    this.removeText = function() {
        element.removeChild(element.childNodes[0]);
    }

    this.setAttribute = function(attribute,value) {
        element.setAttribute(attribute,value);
    }

    this.removeAttribute = function(attribute) {
        element.removeAttribute(attribute);
    }

    this.appendTo = function(parent) { // Works but not on element instances of the constructor
        parent.appendChild(element);
    }

    this.details = function(){
        alert(
            "Type: " + element + 
            "\n\"typeof\": " + typeof(element) // Shouldn't need this right?
        );
    }
}

Example

ul = new element("ul");
ul.appendTo(body); // works fine if BODY is actually an HTML tag

alert(body); // gives me [object HTMLBodyElement] :)
alert(ul); // gives me [object Object] >(

li = new element("li"); // works :)
li.setText("list item text"); // works :)
li.appendTo(ul); // doesn't work >(

If I could just figure out how to append JavaScript-created (child) elements to other JavaScript-created (parent) elements, I'd be golden. I think it has to do with the return value of instantiated elements made by the constructor.

EDIT

1) Possible answer

@carter-sand Thank you. Adding a new this.appendChild method works but reinvents the wheel of HTML object's built in appendChild method.

2) Possible answer

@s4mok Thanks for the hint. Changing var element to this.elem works but creates a funky interface:

li.appendTo(ul.elem); 

vs.

li.appendTo(ul);

I'm trying to emulate a private member.

Both answers work but neither return the value [object HTMLWhateverElement] when I do :

alert(li);

Is there a way to reap the benefits of all of the above?

Was it helpful?

Solution 2

Your function returns an instance of itself [object Object] when created using the "new" keyword. You can override that by specifically returning your element. However you will then need to change "this" to your element instead because "this" refers to the function new instance. Also as suggested it may be less confusing if you changed "element" to something else like "newElement".

function element(tagName) {
    var element = document.createElement(tagName);

    element.setText = function(elementText) {
        if(element.childNodes.length < 1) {
            var text = document.createTextNode(elementText);
            element.appendChild(text);
        } else {
            element.childNodes[0].nodeValue = elementText;
        }
    }

    element.removeText = function() {
        element.removeChild(element.childNodes[0]);
    }

    element.setAttribute = function(attribute,value) {
        element.setAttribute(attribute,value);
    }

    element.removeAttribute = function(attribute) {
        element.removeAttribute(attribute);
    }

    element.appendTo = function(parent) { // Works but not on element instances of the constructor
        parent.appendChild(element);
    }

    element.details = function(){
        alert(
            "Type: " + element + 
            "\n\"typeof\": " + typeof(element) // Shouldn't need this right?
        );
    }
    return element;
}


ul = new element("ul");
ul.appendTo(document.body); // works fine if BODY is actually an HTML tag

alert(document.body); 
alert(ul); 

li = new element("li");
li.setText("list item text"); 
li.appendTo(ul); 

OTHER TIPS

ul = new element("ul");

The above line is instantiating the function element() and the instance which is assigned to ul is an object and not HTMLWhateverElement

ul.appendTo(body); // works fine if BODY is actually an HTML tag

The above works because your code is :

this.appendTo = function(parent) { // Works but not on element instances of the constructor
    parent.appendChild(element);
}

whereas the parent is body and an HMTL Element and has a method appendChild, and the element that you are appending is the element from this line:

var element = document.createElement(tagName);

Why the below code does not work?

li = new element("li"); // works :)
li.setText("list item text"); // works :)
li.appendTo(li); // doesn't work >(

The answer to that is first of all li is not a HTML Element which the code

this.appendTo = function(parent) { // Works but not on element instances of the constructor
    parent.appendChild(element);
}

will fail since the instance li is not an html element but rather an object instance of function element()

Another error in this code is that you have a circular li.appendTo(li); which if you inspect your code, you are appending as child li to itself. something like a paradox or a circular dependency.

EDIT:

My Recommendation:

  • First of all, maybe change the name of your "element" inside the function element to avoid confusion. :D
  • Expose the var element = document.createElement(tagName); so that you could access it from the parameter parent of your method appendTo which will allow you to use parent.getTheExposedElement().appendChild ()

If I run your example, I notice the following error message in the console:

Uncaught TypeError: Object #<element> has no method 'appendChild'

This is because your custom element instance does not have the appendChild method that you're using in appendTo. You need to add one to your constructor, like this:

this.appendChild = function(child) {
    element.appendChild(child);
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top