javascript 如何定位HTML表中每行的每个输入框?

cnh2zyt3  于 2023-04-28  发布在  Java
关注(0)|答案(3)|浏览(123)

我做了一个HTML表格,并使用本地JSON数据填充。我已经取得了这样的表,它有一个编辑按钮,我希望它这样,当我点击按钮,它使输入框在各自的行可编辑。
我已经有了一些工作,但我的代码使它这样,当我点击编辑按钮图标的任何一行,它将只使它的顶部行是可编辑的,而不是我点击编辑图标的当前行。这是我的代码。

function buildTable(data) {
var table =document.getElementById("myTable")

for (let i =0; i < data.length; i++) {

let row = `<tr>
             <td>${[i+1]}</td>
             <td id=customerKey>${data[i].customerKey}</td>
             <td id=currency>${data[i].currency}</td>
             <td id=currency>${data[i].suffix}</td>
             <td><button type="button" onclick="editRow()>
          </tr>`

table.innerHTML += row
}
}

editRow()的函数是

function editRow() {
         document.getElementById("customerKey").contentEditable = true;
         document.getElementById("currency").contentEditable = true;
         document.getElementById("suffix").contentEditable = true;

我不知道为什么它只针对表的顶行,而不是我点击图标的相应行?或者有更好的方法吗?

46qrfjad

46qrfjad1#

首先,id * 必须 * 是唯一的--你的id在每一行上都是相同的,它会找到第一个。然后,您需要找到所有相关的<td>,并使 them contentEditable = true。此外,您没有任何输入框。您有表格单元格,您正在使其内容可编辑。你可以很容易地使用输入并将其初始化为disabled,然后将disabled设置为false。

function buildTable(data) {
  var table = document.getElementById("myTable")

  for (let i = 0; i < data.length; i++) {

    let row = `<tr>
             <td>${[i+1]}</td>
             <td class="editable" >${[i+1]}</td>
             <td class="editable" >${[i+1]}</td>
             <td><button type="button" onclick="editRow(this);">
          </tr>`

    table.innerHTML += row
  }
}

function editRow(button) {
  button.closest("tr").querySelectorAll("td.editable").forEach(
    function(e) {
      e.contentEditable = true;
    }
  );
332nm8kg

332nm8kg2#

您可以选择为每个表格单元格/元素指定唯一的id

function buildTable(data) {
  var table = document.getElementById('myTable');

  for (let i = 0; i < data.length; i++) {
    let row = `<tr>
           <td id="id-${i}">${i + 1}</td>
           <td id="customerKey-${i}">${data[i].customerKey}</td>
           <td id="currency-${i}">${data[i].currency}</td>
           <td id="suffix-${i}">${data[i].suffix}</td>
           <td><button type="button" onclick="editRow(${i})">Edit</button></td>
        </tr>`;

    table.innerHTML += row;
  }
}
function editRow(i) {
  document.getElementById(`customerKey-${i}`).contentEditable = true;
  document.getElementById(`currency-${i}`).contentEditable = true;
  document.getElementById(`suffix-${i}`).contentEditable = true;
}

buildTable([
  { customerKey: '1', currency: 'USD', suffix: '.exe' },
  { customerKey: '2', currency: 'USD', suffix: '.jpg' },
]);
<table id="myTable" border="1"></table>
3phpmpom

3phpmpom3#

其他答案已经解释了为什么你当前的代码不起作用:ids必须是唯一的。所以a)当你循环你的数据时,你在每一行添加相同的id,B)当你指向那些行单元格时,浏览器将返回第一个与你的查询选择器匹配的元素,即只返回第一行中的单元格。正如他们所建议的那样,您可以通过在每个单元格的id中添加索引,或者使用classes或。..
Data attributes在这里可能非常有用,而不是元素id。您可以添加一个索引来标识行,并在每个单元格上添加一个索引来标识其类型。当你点击一个按钮/编辑一个字段时,你可以使用closest找到最近的一行,这反过来又将确定数组中的哪个对象应该被更新/删除等等。
例如:当你遍历数据时,你需要向行添加一个rowid数据属性:

<tr data-rowid="${id}">

以及celltype到每个小区:

<td>
  <input
    data-celltype="${key}"
    type="text"
    value="${value}"
  />
</td>

例如,当您单击一个按钮时,您可以使用closest查找最近的行,并对其执行操作。在这里,我们将在单击“删除”按钮时从表中删除一行。

const parent = e.target.closest('tr');
parent.remove();

问题仍然是如何确保对表的更改反馈到数据集。我不知道你是否已经走到这一步,但我冒昧地写了一个小例子。它与您的代码问题有点偏离,但您可能会发现这里的一些代码很有用。
1.它使用了Redux的基本状态管理原则--一个reducer,它根据传递给它的操作返回一个新的状态,一个store,它返回两个函数dispatchgetState,这两个函数可以用来更新状态,并从中获取数据。
1.表格单元格从一开始就是可编辑的,因此无需单击按钮即可进行编辑。唯一的按钮是删除按钮。
1.当单击delete按钮时,处理程序从row元素的data属性中获取rowid,向存储区发送一个操作以从数据中删除row对象,然后删除该行。
1.当输入字段被更改时,处理程序获取rowid、单元格的celltype数据属性值和输入值,并将该信息分派到存储区,存储区返回一个新状态,其中由rowid标识的对象用新值更新。

const initialState=[{id:1,key:"111",currency:"GBP",suffix:"pla"},{id:2,key:"2222",currency:"EUR",suffix:"xyz"},{id:3,key:"333",currency:"USD",suffix:"abc"}];

// The reducer returns a new state dependant on the
// type of action dispatched to it along with a payload
// The payload may be a single value (see "delete")
// or it maybe an object (see "edit") which can be used
// to update the the state with new values.
function reducer(state, action) {

  // Destructure the type and payload from
  // the action object
  const { type, payload } = action;

  switch (type) {

    // `filter` out the object the id of which
    // matches the rowid passed in the payload
    case 'delete': {
      return state.filter(obj => {
        return obj.id !== Number(payload);
      });
    }

    // `map` over the state and return a new array
    // updating the value of the celltype of the
    // appropriate row
    case 'edit': {
      const { rowid, celltype, value } = payload;
      return state.map(obj => {
        if (obj.id === Number(rowid)) {
          obj[celltype] = value;
          return obj;
        }
        return obj;
      });
    }

    default: return state;

  }

}

// The store allows us to dispatch and get the
// current state. It returns an object with the
// "dispatch" and "getState" functions
function createStore(reducer, initialState) {

  let state = [ ...initialState ];

  function dispatch(action) {
    state = reducer(state, action);
  }

  function getState() {
    return state;
  }

  return { dispatch, getState };

}

// initialise the store
const { dispatch, getState } = createStore(reducer, initialState);

// Cache the DOM elements
const button = document.querySelector('.showstate');
const tbody = document.querySelector('tbody');

// Attach a listener to the "showstate" button,
// and two listeners to the table body, one to listen
// for input events, the other to listen for click events
button.addEventListener('click', showState);
tbody.addEventListener('input', handleInput);
tbody.addEventListener('click', handleClick);

// Shows the current state
function showState() {
  console.log(JSON.stringify(getState()));
}

// If the tbody listener catches a click event
// it checks to see if it came from a "delete" button.
// Then it finds the closest row element, and grabs its
// rowid from the data attribute. It dispatches an action
// to the store (which removes that object from the state),
// and then removes the row from the table
function handleClick(e) {
  if (e.target.matches('.delete')) {
    const parent = e.target.closest('tr');
    const { rowid } = parent.dataset;
    dispatch({ type: 'delete', payload: rowid });
    parent.remove();
  }
}

// If the tbody listener catches an input event it checks to
// see if the element matches an input element, grabs the rowid
// from the row element, and the celltype from the input element.
// Then it dispatches an action to the store to update the value
// of the object property where the rowid matches the object id
function handleInput(e) {
  if (e.target.matches('input')) {
    const { dataset: { rowid } } = e.target.closest('tr');
    const { dataset: { celltype }, value } = e.target;
    dispatch({ type: 'edit', payload: { rowid, celltype, value } });
    e.target.classList.add('edited');
  }
}

// Creates an input cell
function createCell(key, value) {
  return `
    <td>
      <input
        data-celltype="${key}"
        type="text"
        value="${value}"
      />
    </td>
  `;
}

// `map` over the state data. For each object create
// a row of cell data using its values. As `map` returns an
// array we need to `join` it up into an HTML string so we can
// add it to the table body
const html = getState().map(obj => {
  
  const { id, key, currency, suffix } = obj;
  
  return `
    <tr data-rowid="${id}">
      <td>${id}</td>
      ${createCell('key', key)}
      ${createCell('currency', currency)}
      ${createCell('suffix', suffix)}
      <td>
        <button type="button" class="delete">
          Delete
        </button>
      </td>
    </tr>
  `;

}).join('');

// Add the HTML to the table body
tbody.innerHTML = html;
table { border-collapse: collapse; }
thead { background-color: #efefef; }
th { text-transform: uppercase; }
td { padding: 0.25rem; border: 1px solid #dfdfdf; width: fit-content; }
input { width: 100px; }
.showstate { margin-top: 0.25rem; }
.edited { background-color: #aaEEaa; }
.as-console-wrapper { max-height: 20% !important; }
<table>
  <thead>
    <tr>
      <th>#</th>
      <th>key</th>
      <th>currency</th>
      <th>suffix</th>
    </tr>
  </thead>
  <tbody>
  </tbody>
</table>
<button type="button" class="showstate">
  Show state
</button>

相关问题