You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript动态元素onclick调用方法报错:readListItem未定义求助

问题

我是TypeScript新手,正在开发一款CRUD应用,该应用会生成带按钮的表格,点击按钮就能填充表单更新对应条目。现在输入条目ID点按钮能实现功能,但想直接给按钮绑定对应条目ID简化操作。

我写了两个方法:readAllItems用来获取所有条目并生成表格,readListItem根据ID获取指定条目。原生JS里直接在onclick属性加带参数的函数调用没问题,但现在生成的HTML里虽然有调用readListItem的语句,点击按钮却报错“readListItem未定义”,就算把readListItem放在readAllItems前面也没用。

编辑说明:已经更新代码,删掉了不必要的行,现在只需要把forEach循环里生成的按钮绑定到readListItem方法,让它根据条目ID执行功能。

private readAllItems() : void{
    
    this._getListItems().then(listItems => {
      let html: string = '<table border=1 width=100% style="border-collapse: collapse;">';
      html += '<th>ID Edit</th><th>Title</th> <th>Vendor</th><th>Description</th><th>Name</th><th>Version</th>';

    listItems.forEach(listItem => {
      html += `<tr>     
      <td><button class="editButton" onclick=${this.readListItem(listItem.Id)} data-item-id="${listItem.Id}">Edit</button></td>       
      <td>${listItem.Title}</td>
      <td>${listItem.SoftwareVendor}</td>
      <td>${listItem.SoftwareDescription}</td>
      <td>${listItem.SoftwareName}</td>
      <td>${listItem.SoftwareVersion}</td>      
      </tr>`;
    });
    html += '</table>';
    const listContainer: Element = this.domElement.querySelector('#divStatus');
  
    listContainer.innerHTML = html;
    });
  }

private readListItem(id): void {

    this._getListItemByID(id).then(listItem => {

    document.getElementById("txtSoftwareTitle")["value"] = listItem.Title;
    document.getElementById("ddlSoftwareVendor")["value"] = listItem.SoftwareVendor;
    document.getElementById("txtSoftwareDescription")["value"] = listItem.SoftwareDescription;
    document.getElementById("txtSoftwareName")["value"] = listItem.SoftwareName;
    document.getElementById("txtSoftwareVersion")["value"] = listItem.SoftwareVersion;
    
    
    })
    .catch(error => {
      let message: Element = this.domElement.querySelector('#divStatus');    
      message.innerHTML = "Read: Could not fetch details.. "+error.message;
    });
  }
解决方案

你的问题出在两个核心点:

  1. 内联onclick的写法错误:当前代码onclick=${this.readListItem(listItem.Id)}会在生成HTML时立即执行readListItem方法,最终onclick属性值是该方法的返回值(这里是undefined),点击按钮时自然无有效执行逻辑。
  2. 私有方法的作用域问题:readListItem是类的私有方法,内联onclick代码属于全局作用域,无法访问类的私有成员,因此会提示“readListItem未定义”。

下面是两种可行的解决方式:

方法一:事件委托(推荐)

生成HTML时仅保留data-item-id属性,给表格容器绑定统一的点击事件,通过事件冒泡处理按钮点击:

private readAllItems() : void{
    
    this._getListItems().then(listItems => {
      let html: string = '<table border=1 width=100% style="border-collapse: collapse;">';
      html += '<th>ID Edit</th><th>Title</th> <th>Vendor</th><th>Description</th><th>Name</th><th>Version</th>';

    listItems.forEach(listItem => {
      html += `<tr>     
      <td><button class="editButton" data-item-id="${listItem.Id}">Edit</button></td>       
      <td>${listItem.Title}</td>
      <td>${listItem.SoftwareVendor}</td>
      <td>${listItem.SoftwareDescription}</td>
      <td>${listItem.SoftwareName}</td>
      <td>${listItem.SoftwareVersion}</td>      
      </tr>`;
    });
    html += '</table>';
    const listContainer: Element = this.domElement.querySelector('#divStatus');
  
    listContainer.innerHTML = html;
    // 添加事件委托
    listContainer.addEventListener('click', (e) => {
      const target = e.target as HTMLElement;
      if (target.classList.contains('editButton')) {
        const itemId = target.dataset.itemId;
        if (itemId) {
          this.readListItem(itemId);
        }
      }
    });
    });
  }

这种方式无需逐个绑定事件,后续表格内容更新时事件逻辑依然有效,同时避免了作用域问题。

方法二:创建真实DOM元素绑定事件

不通过字符串拼接HTML,而是创建真实DOM节点后直接绑定事件,用箭头函数保留类实例的this指向:

private readAllItems() : void{
    
    this._getListItems().then(listItems => {
      const table = document.createElement('table');
      table.style.border = '1px solid';
      table.style.width = '100%';
      table.style.borderCollapse = 'collapse';

      // 构建表头
      const headerRow = document.createElement('tr');
      ['ID Edit', 'Title', 'Vendor', 'Description', 'Name', 'Version'].forEach(text => {
        const th = document.createElement('th');
        th.textContent = text;
        headerRow.appendChild(th);
      });
      table.appendChild(headerRow);

      // 构建表格行
      listItems.forEach(listItem => {
        const row = document.createElement('tr');
        
        // 编辑按钮单元格
        const buttonCell = document.createElement('td');
        const editButton = document.createElement('button');
        editButton.className = 'editButton';
        editButton.textContent = 'Edit';
        // 绑定点击事件,箭头函数确保this指向当前类实例
        editButton.addEventListener('click', () => {
          this.readListItem(listItem.Id);
        });
        buttonCell.appendChild(editButton);
        row.appendChild(buttonCell);

        // 其他单元格
        [listItem.Title, listItem.SoftwareVendor, listItem.SoftwareDescription, listItem.SoftwareName, listItem.SoftwareVersion].forEach(text => {
          const cell = document.createElement('td');
          cell.textContent = text;
          row.appendChild(cell);
        });

        table.appendChild(row);
      });

      const listContainer: Element = this.domElement.querySelector('#divStatus');
      listContainer.innerHTML = '';
      listContainer.appendChild(table);
    });
  }

这种方式通过操作真实DOM元素,直接绑定事件,彻底规避内联事件的作用域问题。

内容的提问来源于stack exchange,提问作者OMGDrAcula

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 17:05:18