skip to Main Content

In my example example I like to capture a keydown event inside an editable table:

  1. Click/select a cell
  2. Press delete
<!-- index.html -->
    <table contenteditable="true">
        <tr>
            <td>Cell 1</td>
            <td>Cell 2</td>
            <td>Cell 3</td>
        </tr>
    </table>

When I use for example a simple simple click event it works fine:

    //script.js
    const tdElements = document.querySelectorAll("td");
    function clickHandler(){this.remove()}
    tdElements.forEach((item)=>{item.addEventListener("click", this.clickHandler)});

But when I try to catch the delete key event, only the cell gets edited (the keydown event is not catched).
I suppose the reason for this is that the keyevents for editing the cell is overriding my added event listener. How can make the event listener to catch the delete key command?

    //script.js
    const tdElements = document.querySelectorAll("td");
    function keydownHandler() {console.log(event.key)}; //console.log does not work
    tdElements.forEach((item)=>{item.addEventListener("keydown", keydownHandler)})

When I simply add the key catcher to the document the key gets logged as expected.

    //script.js
    function keydownHandler() {console.log(event.key)}; //console.log works fine
    document.addEventListener("keydown", keydownHandler)

2

Answers


  1. Chosen as BEST ANSWER

    After investigation I found a way to delete certain cells by selecting and afterwards pressing delete. By adding an event listener to the document it finally works.
    Still I dont know why the event listeners don't work for the td-elements.

        <!-- index.html -->
        <table contenteditable="true">
            <tr>
                <td>Cell 1</td>
                <td>Cell 2</td>
                <td>Cell 3</td>
            </tr>
        </table>
    
        //script.js
        const tdElements = document.querySelectorAll("td");
        var selectedCell;
    
        //event handlers
        function selectCell() {
            selectedCell = this; //assign selected cell
            console.log(selectedCell)};
        function deleteCell() {
            if(event.key == "Delete"){ //catch the delete event
            selectedCell.remove()}; 
            event.preventDefault()} //prevent the event from doing further text changes
    
        //Assigning event handlers
        tdElements.forEach(td => td.addEventListener("click", selectCell));
        document.addEventListener("keydown", deleteCell);
    

  2. Problem

    You set an event listener for the keydown event on all your td elements however these elements don’t generate keyboard events. From MDN documentation:

    Keyboard events are only generated by <input>, <textarea>, <summary> and anything with the contentEditable or tabindex attribute. If not caught, they bubble up the DOM tree until they reach Document.

    In your case, the table element would generate the event. Demo below:

    const tdElements = document.querySelectorAll("td");
    
    function keydownHandler() {
      console.log(event.key);
    }
    
    document
      .getElementById("table")
      .addEventListener("keydown", keydownHandler);
    
    tdElements.forEach((item) => {
      item.addEventListener("keydown", keydownHandler);
    });
    <table id="table" contenteditable="true">
      <tr>
        <td>Cell 1</td>
        <td>Cell 2</td>
        <td>Cell 3</td>
      </tr>
    </table>

    Solution

    You could add the tabindex attribute to each of your tds. This will allow them to emit the keydown event. There’s the additional benefit that these are now navigable via the keyboard. Demo below:

    const tdElements = document.querySelectorAll("td");
    
    function keydownHandler() {
      console.log(event.key);
    }
    
    tdElements.forEach((item) => {
      item.addEventListener("keydown", keydownHandler);
    });
    <table id="table" contenteditable="true">
      <tr>
        <td tabindex="0">Cell 1</td>
        <td tabindex="0">Cell 2</td>
        <td tabindex="0">Cell 3</td>
      </tr>
    </table>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search