5

Possible Duplicate:
In Javascript, can you extend the DOM?

I'm trying to add methods and properties to the Element. It is not listed as a global class. I can extend String like this:

String.prototype.dosomething = function { ... };

I try like this (it's bigger, this is the basic):

function $id(str){
    this.element = document.getElementById(str); 
    return element;
}
var myElem = $id('myId'); // WORKS !!!
$id.prototype.dosomethig = function ( ... }; 
var myValue = $id('myId').dosomething(); // DOESN'T WORK !!!

I try in other ways but the point it's always the same, when I try to extend the class, it doesn't work. Is there a way to avoid this? I know jQuery do this, but I want to do my onwn - if they can, I can... right?

Edit: Below a code already working in Safari and Firefox...

Element.prototype.pos = function(){
    var curleft = this.offsetLeft;
    var curtop = this.offsetTop;
    var scrleft = this.scrollLeft;
    var scrtop = this.scrollTop;
    var pElement = pElementScr = this.offsetParent
    while(pElement){
        curleft += pElement.offsetLeft;
        curtop += pElement.offsetTop;
        pElement = pElement.offsetParent;
    }
    while(pElementScr){
        scrleft += pElementScr.scrollLeft;
        scrtop += pElementScr.scrollTop;
        pElementScr = pElementScr.offsetParent;
    }
    return {x:this.offsetLeft, y:this.offsetTop};
}

It gives the position of a div even inner of a lot of other divs. I'll try to test in IE8, after solve a lot of other issues of my library.

Community
  • 1
  • 1
Gustavo
  • 1,673
  • 4
  • 24
  • 39

4 Answers4

4

In firefox, chrome and IE8+ elements inherit from Element.prototype so you must do:

Element.prototype.doSomething = function() {
    alert("hello");
};

Extending host prototypes is very fragile and not recommended but should be fine if you are just playing around. The main reason is that DOM specification doesn't specify prototypal implementations but just interfaces, elem.appendChild() should just work, it doesn't have to be in some prototype.


This:

function $id(str) {
    this.element = document.getElementById(str);
    return element;
}

Only worked because of the undesired behavior that this refers to the global object when a function is invoked without any object context (It should just flat out throw an error at the mere sight of this, though strict mode somewhat fixes this by setting it to undefined). You are making a global variable element (since property assignments to the global object become global variables) and then returning the global variable.

Esailija
  • 138,174
  • 23
  • 272
  • 326
2

Instead of extending the DOM object, why not wrap it, sort of like jQuery does.

var myLib = {
   addWrapper: function ( id ) {
      return new this.WrapperClass( document.getElementById( id ) );
   },
   WrapperClass: function ( element) {
      this.element = element;
   }
};
MyLib.WrapperClass.prototype.someMethod = function() {
   alert( this.element);
}

var wrappedElement = myLib.addWrapper( 'someid' );
wrappedElement.someMethod();
dqhendricks
  • 19,030
  • 11
  • 50
  • 83
0
$id('myId').dosomething()

$id('myId') is an element.

You do not have a function called doSomething in 'Element', you have it on $id, which is a function. Actually what happens when you add a function to a function, is it possible??

srini.venigalla
  • 5,137
  • 1
  • 18
  • 29
  • He is not assigning a function to a function, he assigns it to `$id.prototype.dosomethig` and `$id.prototype` is an object. But of course, since functions are object, they can have arbitrary properties. – Felix Kling Aug 02 '12 at 20:54
  • @Felix right.. $id returns an element, he added a function to it, then an instance of it created for 'myId', why doesn't it get the extension? – srini.venigalla Aug 02 '12 at 20:59
  • He returns `element` which should actually throw an error because it is not defined. He has to return `this` from `$id`. – Felix Kling Aug 02 '12 at 21:01
  • Javascript is unclear about. A class is created the same way as a function, is just a matter of "point of view". – Gustavo Aug 02 '12 at 23:10
0

First of all, extending DOM is often (read: always) a bad choice. If you want to write fast, cross-browser code, you shouldn't extend DOM or other native objects (Object, String...). Extending native objects may also cause compatibility issues with libraries etc. If you want to know more about the subject, I'd suggest you to take a look at this excellent blog post: http://perfectionkills.com/whats-wrong-with-extending-the-dom/

If supporting older versions of IE (IE6 && 7) is not important to you, then this is what you want:

Element.prototype.doSomething = function () {
    // Your code here
};

In your example, the problem is, that $id returns an element. Your "doSomething" is attached to the function $id, not to the element it returns.

Doing this works:

function $id(str){
    this.element = document.getElementById(str); 
    return this;
}
undefined
  • 27
  • 1
  • 4
  • Good. This solve almost everything IF works in IE8. I do not intent compatibility with older versions. Funny is that none of my js references list Element as a class. – Gustavo Aug 02 '12 at 23:06