I am writing a HTMLElement and trying to add anchor tags to the html dynamically. I am able to add anchor tags to innerHtml (createLink
function in my code), but onClick event handlers are missing. How can I attach onClick event handlers in javascript. I am writing my code in typescript and transpiling to js using babble and 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');
}
}
When it renders on the UI, I see this anchor tag, but the onClick event handler is missing.
<a href="#">Details</a>
答案 0 :(得分:0)
这是因为通过on<event>
属性添加事件处理程序不会影响HTML属性。
看看this。
答案 1 :(得分:0)
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 fragment serialization algorithm序列化锚元素。算法的步骤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);
设计目的是在单击链接时显示员工详细信息。限制是,如果必须在内部将链接作为文本处理,则单击处理程序将不得不从代码片段中调用全局单击处理程序-这会闻起来。
一种替代方法是将单击处理委托给在构造过程中添加到自定义元素的单个处理程序,并添加data属性以链接包含用于访问私有类数据的雇员索引的元素(无法通过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>
请注意上面的代码段具有
renderHtml
以将getEmployeeTemplate
用作地图函数,createLink
,createLink
。还请注意,使用自定义标记创建自定义元素时不能有子节点-因此测试代码异步调用renderHTML
。