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)
source to share
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.
source to share
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.
source to share
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?
source to share