-2

I want a javascript function to get a data-attribute of an element. I want to use it on native JS' elements.

I've searched around for prototype getters, but I just cant wrap my head around how it works (javascript isnt my cup of tea yet).

What I want:

this.myCustomFunction('fooBar'); // the `this` element
document.getElementById('ExampleId').myCustomFunction('fooBar'); // another way of selecting

All examples I find are on objects which I create myself, I want one like the example above.

To provide the benchmark, here you can find the benchmark

If someone could give me a small example, and some explanation on how the code flows, that'd be great (or on how this is called, for future reference).


The first comment recommands me not to do things this way. I'll explain my goal a bit more, in case there is another solution. This is where I'm at now:

Object.prototype.cms_getDataAttr = function(dataname){
    // IE upto 10 doenst work with dataset, so use the slower 'getAttribute'
    if( typeof this.dataset == 'undefined'){
         return this.getAttribute('data-'+dataname);
    }
    else{
        // I want to use this one instead, benchmarked this is ALOT faster
        return this.dataset.bigsrc;
    }
}
Martijn
  • 15,791
  • 4
  • 36
  • 68
  • 1
    Don't extend dom objects, that's the rule. The why has already been discussed at length, but just as a short reminder : not cross-platform, very very slow, not library/developer-friendly, etc. – Ven Oct 15 '13 at 12:02
  • There is one already: `document.getElementById('ExampleId').getAttribute('data-foo');` – David Hellsing Oct 15 '13 at 12:08
  • Ok, can't see anythings wrong with my idea, but im not pro at this, so im gonna take your word for it. I expanded my question, maybe its a bit more clear now – Martijn Oct 15 '13 at 12:08
  • @david, that is slow compared to the dataset option, thats why I want the dataset if possible – Martijn Oct 15 '13 at 12:09
  • You could do what you want easily using jQuery's data() function or similar functions in other popular Javascript libraries. Is there some reason you want to avoid using a library? – Matt Browne Oct 15 '13 at 12:11
  • Maybe off topic, but you do know that *dataset* and *data attributes* uses different property syntax? Also, `getAttribute` actually seems to be faster: http://jsperf.com/html5-data-attribute-dataset-vs-getattribute – David Hellsing Oct 15 '13 at 12:12
  • @MattBrowne: Yes, I prefer as close to native as possible. Performace is an issue, the jQuery `data()` is about the same as the `setAttribute()` in JS – Martijn Oct 15 '13 at 12:14
  • @David. Hm, yes, its faster this time. It wasnt last time I benchmarked it. Odd. That makes this question obsolite. Im going to leave this last comment for a bit and delete the question. Thanks everyone – Martijn Oct 15 '13 at 12:16
  • 2
    @Martijn: http://perfectionkills.com/whats-wrong-with-extending-the-dom/, [How to define method in javascript on Array.prototype and Object.prototype so that it doesn't appear in for in loop](http://stackoverflow.com/q/13296340/1048572) – Bergi Oct 15 '13 at 12:17

3 Answers3

1

I'm not sure this is what you want, but you can read and write html attributes (including data-attributes) on an element with setAttribute and getAttribute :

element.getAttribute("data-foo"); // ==> Returns the value of the data-attribute
element.setAttribute("data-foo", "newValue"); // ==> Changes the value of the data-attribute to "newValue"
Sebastien C.
  • 4,649
  • 1
  • 21
  • 32
  • Please check the comment in my last bit of code (I editted it). I am aware of those methods, but I don't want to – Martijn Oct 15 '13 at 12:10
  • Could you delete this answer? I cant delete my topic :) the benchmark gave another result this time, so im not gonna do all that difficult and just use get/setAttribute – Martijn Oct 15 '13 at 12:18
  • Although this answer apparently wasn't helpful to you, you never know who might find this page in the future who has a slightly different question than you. So answers shouldn't generally be deleted on StackOverflow unless they are really inappropriate. – Matt Browne Oct 15 '13 at 12:32
1

In general, you should avoid extending the prototypes of native Javascript objects. One of the biggest reasons for this recommendation is that it can cause conflicts if different programmers use the same function names for their native-prototype extensions, meaning the first programmer's functions would now do something completely different. What if you wanted to turn some of your code into a reusable library at some point to be shared with other programmers or projects? If one of those other programmers had his/her own getDataAttr function that did something different than yours, then either your code or the other programmer's would need to be rewritten. So it's better if everyone avoids extending native objects, except to write shims to add support to older browsers for features that have since become standard.

As @Bergi pointed out, in this case you could actually use the native dataset property available on newer browsers. Using a shim, e.g. this one, you could now simply access the dataset property of any element regardless of which browser you're using, meaning you no longer need a custom function. That's what I'd recommend in this case because when those old browsers become outdated, you won't even need the shim anymore and obviously native methods perform better and will be easier for other programmers to work with.

In general, one good alternative to extending native prototypes is to do something similar to what jQuery does - write a function that wraps the native object and "extends" it with additional methods, but without actually modifying the object itself. As I said I think the dataset shim is a better solution in this particular case, but this is a useful approach to know about in general. Here's an example:

function ExtendedDomElement(element) {
    this.element = element;
}

ExtendedDomElement.prototype = {
    constructor: ExtendedDomElement,
    getDataAttr: function(dataname) {
        var element = this.element;

        // IE upto 10 doenst work with dataset, so use the slower 'getAttribute'
        if( typeof element.dataset == 'undefined'){
             return element.getAttribute('data-'+dataname);
        }
        else {
            return element.dataset[dataname];
        }
    }
}

function extendDomElement(element) {
    return new ExtendedDomElement(element);
}

function byId(id) {
    return extendDomElement(document.getElementById(id));
}


var fooElementExtended = byId('foo');
var bar = fooElementExtended.getDataAttr('bar');
Matt Browne
  • 12,169
  • 4
  • 59
  • 75
0

This is where I'm at now:

Object.prototype.cms_getDataAttr = function(dataname){
    if (typeof this.dataset == 'undefined')
        return this.getAttribute('data-'+dataname);
    else
        return this.dataset.bigsrc;
};

You should only be extending the DOM Element interface, not all Objects.

Also, you might not write your own dataset method, but just use an existing dataset property shim.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Im going for the set/getAttribute. This wasn't only about that though, a bit more general, for future usage – Martijn Oct 15 '13 at 12:26