Search code examples
javascriptwebpackdraggablebabeljs

Can't seem to get Element.setAttribute to work with webpack/babel


I have the following:

Element.prototype.makeDraggable = (elem = null) => {
    //this.draggable = true;
    this.setAttribute("draggable", "true");
    this.ondragstart = (e) => { e.dataTransfer.setData("text", elem ? elem.id : e.target.id); }
};

When the browser gets to that function it throws an error on the first line:

Drag.js:7 Uncaught TypeError: n.setAttribute is not a function

Where n is the minified name of the element, or so I thought.

enter image description here

as you can see in the picture, this seems to be an Element, but n is.. well I don't know what it is. Am I doing it wrong?

At this same point, if I do this.draggable = true in the console it works just fine... You can also see that I tried doing it in the code but that doesn't work either.

Any ideas?


Solution

  • The this you see in the debugger is the actual this value; the this you see in the source view is the source-mapped version of n, and the value of n isn’t what you want it to be.

    You used an arrow function, so you got lexical this. That’s what arrow functions do. To access the this from call time (what’s generally intended when adding methods to a prototype), use a non-arrow function:

    Element.prototype.makeDraggable = function (elem = null) {
        //this.draggable = true;
        this.setAttribute("draggable", "true");
        this.ondragstart = (e) => { e.dataTransfer.setData("text", elem ? elem.id : e.target.id); }
    };
    

    See also Are 'Arrow Functions' and 'Functions' equivalent / exchangeable?.

    Finally, extending the prototypes you have some of the least control over – browser built-ins – is considered a bad idea. (You could produce a conflict with future extensions to the spec, for example – or with other libraries you use.) A standalone function usually works better:

    const makeDraggable = (target, elem = null) {
        target.draggable = true;
        target.ondragstart = (e) => { e.dataTransfer.setData("text", elem ? elem.id : e.target.id); }
    };