Как прикрепить обработчик щелчка для привязки в пользовательском элементе HTMLE в сценарии Java? - PullRequest
1 голос
/ 17 апреля 2019

Я пишу HTMLElement и пытаюсь динамически добавлять теги привязки в html. Я могу добавить теги привязки к innerHtml (функция createLink в моем коде), но обработчики событий onClick отсутствуют. Как я могу прикрепить обработчики событий onClick в JavaScript. Я пишу свой код в машинописном тексте и переносу его в js, используя babble и webpack.

export class MyCustomElement extends HTMLElement {
constructor() {
    super();
}

private _serviceResponse: Employee[];

connectedCallback() {
    this.getData();
    this.innerHTML = '';
}

getData() {
    let fetch = window.fetch.bind(window);
    fetch('http://localhost/api/v1/values')
        .then(response => {
            return response.json();
        })
        .then((data: Employee[]) => {
            this._serviceResponse = data;
            console.log(this._serviceResponse);
            this.renderHtml();
        });
}

renderHtml() {
    this.innerHTML = `
            <table style="width: 100%;" border="2" >
                <thead>
                    <th>Header1</th>
                    <th>Header2</th>
                    <th>Header3</th>
                </thead>
                <tbody>
                    ${this._serviceResponse.map(employee => { return this.getEmployeeTemplate(employee); })}
                </tbody>
            </table>
            `;
}

getEmployeeTemplate(employee: Employee) {
    switch (employee.Type) {
        case "1":
            return this.getRegularTemplate(order);
        case "2":
            return `<tr><td colspan=3>Test Row}</td></tr>`;
    }
}

getRegularTemplate(emp: Employee): string {
    return `
    <tr>
        <td> ${emp.FirstName} </td>
        <td> ${emp.LastName} </td>
        <td>
            ${this.createLink(emp)}
        </td>
    </tr>
    `;
}

createLink(emp: Employee): string {
    var anchor = document.createElement('a');
    anchor.innerHTML = 'Details';
    anchor.onclick = () =>  { this.handleDetailsClick(emp); };
    anchor.href = '#';
    return anchor.outerHTML;
}

handleDetailsClick(emp: Employee) {
    console.log('Details link clicked: ' + emp);
}

handleDetailsClick() {
    console.log('clicked');
}

}

Когда он отображается в пользовательском интерфейсе, я вижу этот тег привязки, но отсутствует обработчик события onClick.

<a href="#">Details</a>

Ответы [ 2 ]

0 голосов
/ 17 апреля 2019

outerHTML

createLink(emp: Employee): string {
    var anchor = document.createElement('a');
    anchor.innerHTML = 'Details';
    anchor.onclick = () =>  { this.handleDetailsClick(emp); };
    anchor.href = '#';
    return anchor.outerHTML;
}

Оператор return anchor.outerHTML сериализует элемент привязки, используя алгоритм сериализации фрагмента HTML . Шаг 3.2 алгоритма описывает, как он принимает атрибуты элемента (которые имеют текстовые значения) и преобразует их в разметку для элемента.

Эта строка:

 anchor.onclick = () =>  { this.handleDetailsClick(emp); };

не создает атрибут - он создает свойство функции («метод»), прикрепленное к элементу привязки. Он не обрабатывается алгоритмом сериализации и не сохраняется при вставке в пользовательский элемент innerHTML как часть текстовой строки.

Быстрый тест показывает, что даже в виде текста обработчик щелчка должен быть явно добавлен в качестве сериализуемого атрибута:

"use strict";
var anchor = document.createElement('a');
anchor.innerHTML = 'Details';
anchor.onclick = "clickHandle()"
console.log("Setting a property doesn't work: " + anchor.outerHTML);
anchor.setAttribute("onclick", "clickHandle");
console.log("Setting an attribute does work: " + anchor.outerHTML);

Потенциальные решения

Цель дизайна - показать детали сотрудника при нажатии на ссылку. Ограничение состоит в том, что если ссылка должна быть внутренне обработана как текст, ее обработчик щелчков должен будет вызывать глобальный обработчик щелчков из фрагмента кода - который будет пахнуть.

Одной из альтернатив будет делегирование обработки кликов одному обработчику, добавленному к пользовательскому элементу во время создания, и добавление атрибута данных для ссылки на элементы, содержащие индекс сотрудника, используемый для доступа к данным частного класса (который не может быть достигнут из HTML исходный код).

Пример

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Custom Element</title>
<script>

class MyCustomElement extends HTMLElement {
constructor() {
    super();
    this.onclick = event => {
        let link = event.target;
        let index = +link.dataset.index;
        if( link.tagName === 'A' && index >= 0) {
            this.handleDetailsClick( this._serviceResponse[ index]);
        }
    };
    // FOR TESTING ONLY:
    function Employee( index) {
        this.FirstName = "Firstname" + index;
        this.LastName = "Lastname" + index;
        this.Type = "1";
    }
    this._serviceResponse = [ new Employee(1), new Employee(2)];
    setTimeout( this.renderHtml.bind(this), 10)
}
 
renderHtml() {
    this.innerHTML = `
            <table style="width: 100%;" border="2" >
                <thead>
                    <th>Header1</th>
                    <th>Header2</th>
                    <th>Header3</th>
                </thead>
                <tbody>
                    ${this._serviceResponse.map( this.getEmployeeTemplate.bind( this)).join(" ")}
                </tbody>
            </table>
            `;
  }

// ts: getEmployeeTemplate(employee: Employee, number: index ) {
// js:

getEmployeeTemplate( employee, index) {
    switch (employee.Type) {
        case "1":
            return this.getRegularTemplate(employee, index);
        case "2":
            return `<tr><td colspan=3>Test Row}</td></tr>`;
    }
}

// ts: getRegularTemplate(emp: Employee, number: index): string {
// js:

getRegularTemplate(emp, index){
    return `
    <tr>
        <td> ${emp.FirstName} </td>
        <td> ${emp.LastName} </td>
        <td>
            ${this.createLink(index)}
        </td>
    </tr>
    `;
  }

createLink(index){
    return `<a href="#" data-index="${index}">Details</a>`;
}

handleDetailsClick(emp) {
    console.log('Details link clicked: ', emp);
}
} // end of class

customElements.define('employee-s', MyCustomElement);
</script>

</head>
<body>

    <employee-s></employees>

</body>
</html>

Обратите внимание, что приведенный выше фрагмент имеет

  • закомментировал TypeScript, чтобы он мог работать здесь,
  • тестовый код добавлен в конструктор,
  • изменено renderHtml для использования getEmployeeTemplate в качестве функции карты,
  • передал второй параметр карты (то есть индекс массива) в createLink,
  • упрощенный createLink.

Также обратите внимание, что пользовательские элементы не могут иметь дочерние узлы при создании из пользовательских тегов - из-за этого тестовый код вызывает renderHTML асинхронно.

0 голосов
/ 17 апреля 2019

Это потому, что добавление обработчика событий через свойство on<event> не влияет на атрибуты HTML.

Посмотрите на this .

...