0

I'm trying to achieve something to the rhyme of:

document.onload = init();

function Dropdown(dd) {
    this.dd = dd;
    this.exapnded = false;
    this.list = dd.querySelector('.list');

    this.changeState = changeState.bind(this);
    this.dd.addEventListener('click', this.changeState(event));
}

function changeState(e) {
    if(this.expanded == true) {
        this.list.style.display = 'none';
        this.expanded = false;
        e.stopPropagation();
    }
    else {
        this.list.style.display = 'block';
        this.expanded = true;
        e.stopPropagation();
    }
}

function init() {
    let ddCollection = document.getElementsByClassName('dropdown');

    Array.from(ddCollection)
        .forEach(function(ddElement) {
            let dropdown = new Dropdown(ddElement);
            console.log(dropdown);
        }
    );
}

But of course, for the miserable Javascript code I've written given my knowledge of it, when I attempt to execute the above code, it fails with

Uncaught TypeError: this.list is undefined

which implies that whatever I'm doing is not binding my this object to the changeState function.

The result doesn't change if I attempt to try it as follows either

this.dd.addEventListener('click', changeState(event).bind(this));

In such a scenario, how do I achieve it? Vanilla Javascript answers only please.

I've been scratching my head over this and trying every possible solution available on StackOverflow but nothing seems to work. I hope I've conveyed my question appropriately enough. Please drop a comment below in case you need any further clarification.

ikartik90
  • 2,695
  • 6
  • 26
  • 38
  • Have you debugged to see what the value of `this` is? Secondly, have you debugged to see what the value of `dd.querySelector('.list')` is? Your question is also confusing because in the title you ask about passing parameters to a bound function, but in the question itself you ask about binding `this`. – trincot May 23 '21 at 20:53

1 Answers1

1

You should just attach the function to Dropdown.prototype rather than attaching it to the object instance:

Dropdown.prototype.changeState = function (e) {
    if (this.expanded == true) {
        this.list.style.display = 'none';
        this.expanded = false;
        e.stopPropagation();
    } else {
        this.list.style.display = 'block';
        this.expanded = true;
        e.stopPropagation();
    }
};

Also, write the event listener like this, otherwise you immediately call the function instead of registering it for future click reaction.

this.dd.addEventListener('click', event => this.changeState(event));
Guerric P
  • 30,447
  • 6
  • 48
  • 86