Как добавить событие click из метода рендеринга класса javascript, который вызывает метод для того же класса? - PullRequest
0 голосов
/ 22 мая 2018

У меня есть класс JS:

class MyClass {
    constructor() {
    }

    handleClick() {
        alert('clicked');
    }

    render() {
        return `<input type="radio" onClick="${this.handleClick} /><label>My Label</label>"`;
    }
}

window.addEventListener('load', init);

function init() {
    const myClassInstance = new MyClass();
    const el = document.getElementsByClassName('myelement')[0];
    el.insertAdjacentHTML('beforeend', myClassInstance.render());
}

Это делает радиовход в элементе с классом myelement, но когда я нажимаю переключатель, я вижу это:

Uncaught SyntaxError: Unexpected token {

Ошибка относится к методу handleClick.

Мой синтаксис выключен?Если я использую onClick="${this.handleClick()}", я не вижу ошибок, но функция вызывается сразу, а не по щелчку.Что я делаю не так?

Ответы [ 2 ]

0 голосов
/ 22 мая 2018

Если вы хотите, чтобы это onclick работало, тогда вам нужно назначить глобальную функцию для onclick, иначе вы не сможете сделать так, как я сделал быстрое исправление. Это просто временное решение, вы можете выбрать это или @TJ answerтоже хорошо выглядит.

class MyClass {
    constructor() {}

    handleClick() {
        alert('clicked');
    }

    render() {
        const globalId = "h" + Math.floor((Math.random() * 100) + 12345);
        window[globalId] = this.handleClick;
        return `<input type="radio" onClick=window['${globalId}']() />`;
    }
}

window.addEventListener('load', init);

function init() {
    const myClassInstance = new MyClass();
    const el = document.getElementsByClassName('myelement')[0];
    el.insertAdjacentHTML('beforeend', myClassInstance.render());
}
<div class="myelement"></div>
0 голосов
/ 22 мая 2018

Лучше всего не использовать разметку, поскольку функция, которую вы вызываете из обработчика событий в стиле onxyz, должна быть глобальной.

Вместо этого создайте элемент, а затем назначьтефункция к нему:

class MyClass {
    constructor() {
    }

    handleClick(e) {
        alert('clicked');
    }

    render() {
        var input = document.createElement("input");
        input.type = "radio";
        input.addEventListener("click", e => this.handleClick(e));
        return input;
    }
}

window.addEventListener('load', init);

function init() {
    const myClassInstance = new MyClass();
    const el = document.getElementsByClassName('myelement')[0];
    el.appendChild(myClassInstance.render());
}
<div class="myelement"></div>

Обратите внимание на использование функции стрелки, чтобы this было правильным при вызове this.handleClick.Очевидно, вам это не нужно только для alert, но я предполагаю, что вы захотите использовать свойства экземпляра MyClass.(Чтобы получить доступ к элементу, по которому произошел щелчок, используйте e.currentTarget, поскольку он не будет this.)


Если у вас есть сильные предпочтения делать это с разметкой, опция будетбыть:

  • иметь метод initEvents или аналогичный, который должны вызывать потребители класса (как они должны вызывать render)
  • использовать уникальный идентификаторв разметке
  • Используйте этот идентификатор, чтобы найти элемент и подключить события

Или еще лучше: пусть render примет элемент, к которому нужно добавить, и выполните подключение события последобавив его.

Но работая с существующим подходом render:

const MyClass = (() => {
  let nextId = 1;
  class MyClass {
      constructor() {
          this.id = `__MyClass__${nextId++}`;
      }

      handleClick(e) {
          alert('clicked');
      }

      render() {
          return `<input type="radio" id="${this.id}" />`;
      }
      
      initEvents() {
          const e = document.getElementById(this.id);
          if (!e) {
              throw new Error("initEvents must be called after appending the markup from render to the DOM");
          }
          e.addEventListener("click", e => this.handleClick(e));
      }
  }
  return MyClass;
})();

window.addEventListener('load', init);

function init() {
    const myClassInstance = new MyClass();
    const el = document.getElementsByClassName('myelement')[0];
    el.insertAdjacentHTML('beforeend', myClassInstance.render());
    myClassInstance.initEvents();
}
<div class="myelement"></div>
...