Событие слушали несколько раз; Как удалить прослушиватели событий и сохранить контекст на контроллере Stimulus?

У меня есть следующий контроллер на моей странице HTML:

...
<div data-controller="parent">
    <div data-target="parent.myDiv">
        <div data-controller="child">
            <span data-target="child.mySpan"></span>
        </div>
    </div>
</div>
...

Этот дочерний контроллер нам сопоставлен со следующим child_controller.js класс:

export default class {
    static targets = ["mySpan"];

    connect() {
        document.addEventListener("myEvent", (event) => this.handleEvent(event));
    }

    handleEvent(event) {
        console.log(event);
        this.mySpanTarget; // Manipulate the span. No problem.
    }
}

Как вы можете видеть, на connect() контроллера Stimulus, и когда он обнаруживает, что событие было запущено, он регистрирует событие и манипулирует целью span.

Проблема возникает, когда я заменяю содержимое цели myDiv от моего parent_controller.js:

...
let childControllerHTML = "<div data-controller="child">...</div>"

myDivTarget.innerHTML= childControllerHTML;
...

Теперь, когда myEvent когда его зажигают, слушатель выбирает его не один, а два раза. Это означает, что событие обрабатывается дважды, потому что я получаю одно и то же событие, записанное в журнал. При каждой последующей замене дочернего HTML событие регистрируется еще раз, чем раньше.

Я знаю, что можно использовать document.removeEventListener чтобы старый контроллер все еще не слушал события:

export default class {
    static targets = ["mySpan"];

    connect() {
        this.boundHandleEvent = document.addEventListener("myEvent", (event) => this.handleEvent(event));
    }

    disconnect() {
        document.removeEventListener("myEvent", this.boundHandleEvent);
    }

    handleEvent(event) {
        console.log(event);
        this.mySpanTarget; // FAILS. Can't find span.
    }
}

Но, делая это так, я handleEvent метод потерять context как он больше не находит mySpanTarget под this,

Как я могу удалить слушателя из дочернего контроллера, к которому у меня уже нет доступа, поскольку он больше не находится в DOM, при этом сохраняя контекст?

1 ответ

Решение

Я нашел ответ на странице Дискурса StimulusJS.

Нужно использовать bind метод:

export default class {
    static targets = ["mySpan"];

    initialize() {
        this.boundHandleEvent = this.handleEvent.bind(this);
    }

    connect() {
        document.addEventListener("myEvent", this.boundHandleEvent);
    }

    disconnect() {
        document.removeEventListener("myEvent", this.boundHandleEvent);
    }

    handleEvent(event) {
        console.log(event);
        this.mySpanTarget; // Manipulate the span. No problem.
    }
    ...
}

Теперь событие прослушивается только один раз, и контекст не теряется внутри handleEvent метод.

Другие вопросы по тегам