How can I render multiple elements when extending a DIV-Element?

I am trying to "extend" a DIV via Javascript using a newly created div as the prototype for my object.

As I understand Javascript, when creating a new instance of my object through the "new" object the prototype is copied, assigned "this" and then the function is executed (as a constructor).

Everything works, except that whenever I create another object and add it to the DOM, it "replaces" the original div. More precisely: the constructor always changes the same div.

Usage MyTest.prototype = document.createElement("div");

gives me the described behavior, the two commented lines after that in my example code is what I also tried, but to no avail.

I know trying to extend the DOM was frowning, but I want to understand this behavior because I thought I knew how prototypes work and it just doesn't fit my idea.

Here's a minimal example of what I'm trying to do:

<!DOCTYPE html>
<html>
<head>
<title>Div-Prototype-Test</title>
<script type="text/javascript">

var height = 20;
var top = 0;

function MyTest() {
    var r = Math.floor(Math.random() * 256);
    var g = Math.floor(Math.random() * 256);
    var b = Math.floor(Math.random() * 256);

    this.style.backgroundColor = "rgb("+ r +","+ g +","+ b +")";
    this.style.position        = "absolute";
    this.style.width           = "500px";
    this.style.height          = height + "px";
    this.style.top             = top + "px";

    top += height;

    document.getElementsByTagName("body")[0].appendChild(this);
}

MyTest.prototype = document.createElement("div");
// MyTest.prototype = document.createElement("div").cloneNode(true);
// MyTest.prototype = new Element();

window.addEventListener(
    "load", 
    function() {
        var a = new MyTest();
        var b = new MyTest();
        var c = new MyTest();
        var d = new MyTest();
    }
);

</script>
</head>
<body>
</body>
</html>

      

PS: Due to some Javascript-Framework, my search for anything that changes the prototype in Javascript always resulted in hundreds of results that had nothing to do with my problem - please tell me if I missed a question that already discusses this.

Edit:

To make my question clearer:

Here's an example, when I use an object as a prototype - its properties are copied.

function A() {
}

A.prototype = { property: 4 };

A.prototype.set = function(num) {
    this.property = num;
}

window.addEventListener(
    "load", 
    function() {
        var message = "";

        var x1 = new A();
        message += "A1 : "+ x1.property +"\n";

        x1.set(15);
        message += "A1 : "+ x1.property +"\n";

        var x2 = new A();
        message += "A2 : "+ x2.property +"\n";

        alert(message);
    }
);

      

Then there was a warning:

A1 : 4
A1 : 15
A2 : 4

      

The Div in my first example, however, doesn't seem to be copied, it behaves like a Singleton or Monostate. If it doesn't?

  • The Protype is copied to a new object
  • the new object is assigned "this"
  • this is assigned to the constructor
  • this is returned by the constructor (if no return statement is specified)
+3


source to share


3 answers


I found a workaround, it basically works the other way around: the prototype is an empty object and I copy the data of the new objects to the div in the constructor:

var height = 20;
var top = 0;

function deepCopy(fromObject, toObject, depth) {
    if(typeof(fromObject) != "object" || typeof(toObject) != "object") {
        // throw "deepCopy only copies objects"
        return;
    }

    if (typeof(depth) == "undefined") {
        depth = 0;
    } else if (depth > 100) {
        // Recursion depth too high. Abort.
        // throw "deepCopy recursion depth cap hit"
        return;
    }

    for (var key in fromObject) {
        if (typeof(fromObject[key]) == "object" && fromObject[key] != null) {
            if (typeof(fromObject[key].nodeType) != "undefined") {
                toObject[key] = fromObject[key].cloneNode(true);
            } else {
                if (typeof(toObject[key]) != "object") {
                    toObject[key] = {};
                }
                deepCopy(fromObject[key], toObject[key], depth + 1);
            }           

        }
        toObject[key] = fromObject[key];
    }
}    

function MyTest() {
    // This is ugly...
    var self = document.createElement("div");
    deepCopy(MyTest.prototype, self);

    var r = Math.floor(Math.random() * 256);
    var g = Math.floor(Math.random() * 256);
    var b = Math.floor(Math.random() * 256);

    self.style.backgroundColor = "rgb("+ r +","+ g +","+ b +")";
    self.style.position        = "absolute";
    self.style.width           = "500px";
    self.style.height          = height + "px";
    self.style.top             = top + "px";

    top += height;

    document.getElementsByTagName("body")[0].appendChild(self);

    return self;
}

MyTest.prototype = {};
// MyTest.prototype = document.createElement("div").cloneNode(true);
// MyTest.prototype = new Element();

window.addEventListener(
    "load", 
    function() {
        var a = new MyTest();
        var b = new MyTest();
        var c = new MyTest();
        var d = new MyTest();
    }
);

      

While I have the feeling that my deepCopy function is a rather inelegant (and possibly very buggy) way to accomplish the task, the other way around using cloneNode () doesn't work.



My original problem came from this: when a copy is copied, all scalar values ​​are copied and all objects are simply referenced (e.g. copy pointers, the pointer's value is duplicated, but not the data it points to).

Hope this helps someone.

0


source


MyTest.prototype = document.createElement("div");

      

This line is executed only once . It creates an object MyTest.prototype

that is also a DOM element <div>

. Each MyTest

object will receive the same prototype . Therefore, each created object MyTest

will be associated with this one <div>

, which you created only once. You will need to create a new one <div>

for each MyTest

.

Try this pattern:

MyTest = function() {
    var myDiv = document.createElement("div");

    var r = Math.floor(Math.random() * 256);
    var g = Math.floor(Math.random() * 256);
    var b = Math.floor(Math.random() * 256);

    myDiv.style.backgroundColor = "rgb("+ r +","+ g +","+ b +")";
    myDiv.style.position        = "absolute";
    myDiv.style.width           = "500px";
    myDiv.style.height          = height + "px";
    myDiv.style.top             = top + "px";

    top += height;

    document.getElementsByTagName("body")[0].appendChild(myDiv);

    return myDiv;
}

      



This function creates a new <div>

one using a call createElement()

. Then it sets all the required properties for the new one <div>

. Finally, it returns your new one <div>

. So you can call it

var myNewDiv = MyTest();
var myNewDiv = new MyTest();

      

Both options will work. In the second case, a dummy new object is created by the keyword new

, but that doesn't matter, since the new <div>

one created inside the function is actually returned.

+2


source


You mix all kinds of things. Check my answer to this SO question first . Second, object extension Element

can be done, but is not supported by all browsers. Check out this SO question .

It seems to me that you are planning to add items in a document

standardized way. Your code might be overwritten (I changed it a bit):

function appendElement(content,id) {
    var rgb = 'rgb('+ [Math.floor(Math.random() * 256),
               Math.floor(Math.random() * 256),
               Math.floor(Math.random() * 256)].join(',') +')';
    var top  = Math.floor( Math.random() * 300 + 20 );
    var left = Math.floor( Math.random() * 100 + 10 );

    this.style.backgroundColor = rgb;
    this.style.position        = "absolute";
    this.style.width           = "500px";
    this.style.height          = "200px";
    this.style.left            = left+"px";
    this.style.top             = top+"px";
    this.innerHTML             = content || '';
    this.id                    = id || Math.Random*10000+1
    document.getElementsByTagName("body")[0].appendChild(this);
}

      

Now you can use this to add any element to document

using `appendElement like below:

appendElement.call(document.createElement('div'),'empty div');
appendElement.call(document.createElement('span'),'new empty span','span1');

      

Will this be an idea of ​​what you are aiming for?

0


source







All Articles