Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamic Method Call from a Class in ES6

How can a method be called dynamically from a class in ES6?

In ES5 and lower I can do this with the following. JSFiddle example

var App = function() {

    var that = this;

    this.init = function() {
        var elements = document.getElementsByClassName('call-method');

        for(var i = 0; i < elements.length; i++) {
            elements[i].addEventListener('click', function() {
                that['method' + this.dataset.method](this);
            });
        }
    };

    this.methodOne = function(element) {
        console.log(element.innerText);
    };

    this.methodTwo = function(element) {
        console.log(element.innerText);
    };

};

(function() {
    var app = new App();

    app.init();
}());

When I try to do the same in ES6 I get an error Uncaught TypeError: not a function. Is this possible in ES6 or am I doing something wrong here? JSFiddle example

'use strict';

class App {

    constructor() {
        var elements = document.getElementsByClassName('call-method');

        for(var i = 0; i < elements.length; i++) {
            elements[i].addEventListener('click', function() {
                this.constructor['method' + this.dataset.method](this); // Uncaught TypeError: not a function
                App['method' + this.dataset.method](this); // Uncaught TypeError: not a function
            });
        }
    }

    methodOne(element) {
        console.log(element.innerText);
    }

    methodTwo(element) {
        console.log(element.innerText);
    }

}

(function() {
    new App();
}());
like image 567
Enijar Avatar asked Jul 06 '15 14:07

Enijar


2 Answers

I think you're misunderstanding how ES6 classes work. Your first strategy is not going to work, because this.constructor is a method, not a reference to any constructor class. The second won't work, because that would only reference a static method.

Instead:

constructor() {
    var elements = document.getElementsByClassName('call-method');

    for(var i = 0; i < elements.length; i++) {
        elements[i].addEventListener('click', (e) => {
            this['method' + e.target.dataset.method](e);
        });
    }
}

Also arrow functions are going to be a better way to bind the event.

Edit: Updated your fiddle to show it in action - http://jsfiddle.net/dqk8n3xk/3/

like image 83
jacobangel Avatar answered Sep 18 '22 14:09

jacobangel


You can do the following:

'use strict';

class App {

    constructor() {
        var that = this;

        var elements = document.getElementsByClassName('call-method');

        for(var i = 0; i < elements.length; i++) {
            elements[i].addEventListener('click', function() {
                that['method' + this.dataset.method](this);
            });
        }
    }

    methodOne(element) {
        console.log(element.innerText);
    }

    methodTwo(element) {
        console.log(element.innerText);
    }

}

(function() {
    new App();
}());

as shown in this jsfiddle

like image 33
Petar Vasilev Avatar answered Sep 19 '22 14:09

Petar Vasilev