skip to Main Content

Yes, I do know that is an escape character. I am writing a code for a keyboard, and I have to have the key , of course. Now, the problem is, that this key must have a data attribute, which I put as \. Then, when the keys are updated, the JS changed the value to undefined, and everything goes downhill from there. Here is my code:

<html>
  <head>
    <style>
      /* Style the keyboard container */
      #keyboard {
        display: flex;
        flex-wrap: wrap;
        justify-content: center;
        align-items: center;
        margin: 20px auto;
        width: 80%;
        max-width: 800px;
        border: 2px solid #ccc;
        border-radius: 10px;
        padding: 10px;
      }

      /* Style the keyboard keys */
      kbd {
        display: inline-flex;
        justify-content: center;
        align-items: center;
        margin: 5px;
        width: 40px;
        height: 40px;
        border: 1px solid #ccc;
        border-radius: 5px;
        box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
        background-color: #fff;
        font-family: Arial, sans-serif;
        font-size: 18px;
        font-weight: bold;
        color: #333;
        cursor: pointer;
      }

      /* Style the special keys */
      kbd[data-key="tab"],
      kbd[data-key="enter"] {
        width: 80px;
      }

      kbd[data-key="caps"],
      kbd[data-key="backspace"] {
        width: 100px;
      }

      kbd[data-key="shift"] {
        width: 120px;
      }

      kbd[data-key="space"] {
        width: 240px;
      }

      /* Style the active keys */
      kbd.active {
        background-color: #ccc;
      }

      /* Style the output text area */
      #output {
        display: block;
        margin: 20px auto;
        width: 80%;
        max-width: 800px;
        height: 100px;
        border: 2px solid #ccc;
        border-radius: 10px;
        padding: 10px;
        font-family: Arial, sans-serif;
        font-size: 18px;
        color: #333;
        resize: none;
      }
    </style>
  </head>
  <body>
    <!-- Create the keyboard container -->
    <div id="keyboard">
      <!-- Create the keyboard keys -->
      <kbd data-key="`">`</kbd>
      <kbd data-key="1">1</kbd>
      <kbd data-key="2">2</kbd>
      <kbd data-key="3">3</kbd>
      <kbd data-key="4">4</kbd>
      <kbd data-key="5">5</kbd>
      <kbd data-key="6">6</kbd>
      <kbd data-key="7">7</kbd>
      <kbd data-key="8">8</kbd>
      <kbd data-key="9">9</kbd>
      <kbd data-key="0">0</kbd>
      <kbd data-key="-">-</kbd>
      <kbd data-key="+">+</kbd>
      <kbd data-key="backspace" data-exclude="true">Backspace</kbd>
      <kbd data-key="tab" data-exclude="true">Tab</kbd>
      <kbd data-key="q">q</kbd>
      <kbd data-key="w">w</kbd>
      <kbd data-key="e">e</kbd>
      <kbd data-key="r">r</kbd>
      <kbd data-key="t">t</kbd>
      <kbd data-key="y">y</kbd>
      <kbd data-key="u">u</kbd>
      <kbd data-key="i">i</kbd>
      <kbd data-key="o">o</kbd>
      <kbd data-key="p">p</kbd>
      <kbd data-key="[">[</kbd>
      <kbd data-key="]">]</kbd>
      <kbd data-key="\"></kbd>
      <kbd data-key="caps" data-exclude="true">Caps Lock</kbd>
      <kbd data-key="a">a</kbd>
      <kbd data-key="s">s</kbd>
      <kbd data-key="d">d</kbd>
      <kbd data-key="f">f</kbd>
      <kbd data-key="g">g</kbd>
      <kbd data-key="h">h</kbd>
      <kbd data-key="j">j</kbd>
      <kbd data-key="k">k</kbd>
      <kbd data-key="l">l</kbd>
      <kbd data-key=";">;</kbd>
      <kbd data-key="'">'</kbd>
      <kbd data-key="enter" data-exclude="true">Enter</kbd>
      <kbd data-key="shift" data-exclude="true">Shift</kbd>
      <kbd data-key="z">z</kbd>
      <kbd data-key="x">x</kbd>
      <kbd data-key="c">c</kbd>
      <kbd data-key="v">v</kbd>
      <kbd data-key="b">b</kbd>
      <kbd data-key="n">n</kbd>
      <kbd data-key="m">m</kbd>
      <kbd data-key=",">,</kbd>
      <kbd data-key=".">.</kbd>
      <kbd data-key="/">/</kbd>
      <kbd data-key="shift" data-exclude="true">Shift</kbd>
      <kbd data-key="space" data-exclude="true">Space</kbd>
    </div>
    <!-- Create the output text area -->
    <textarea id="output" placeholder="Type something..."></textarea>
  </body>
  <!-- Add the JavaScript code -->
  <script>
    // Get the keyboard container element
    const keyboard = document.getElementById("keyboard");

    // Get the output text area element
    const output = document.getElementById("output");

    // Get all the keyboard keys elements
    const keys = keyboard.querySelectorAll("kbd");

    // Define a variable to store the shift key state
    let shift = false;

    // Define a variable to store the caps lock key state
    let caps = false;

    // Loop through the keys and add event listeners
    for (let key of keys) {
      // Get the data-key attribute value
      let dataKey = key.getAttribute("data-key");

      // Add a click event listener
      key.addEventListener("click", function () {
        // Check which key was clicked
        switch (dataKey) {
          // If backspace, delete the last character
          case "backspace":
            output.value = output.value.slice(0, -1);
            break;
          // If tab, insert a tab character
          case "tab":
            output.value += "t";
            break;
          // If enter, insert a newline character
          case "enter":
            output.value += "n";
            break;
          // If shift, toggle the shift key state
          case "shift":
            shift = !shift;
            key.classList.toggle("active");
            break;
          // If caps, toggle the caps lock key state
          case "caps":
            caps = !caps;
            key.classList.toggle("active");
            break;
          // If space, insert a space character
          case "space":
            output.value += " ";
            break;
          // Otherwise, insert the key value
          default:
            // Check if shift or caps are active
            if (shift || caps) {
              // Insert the uppercase key value
              output.value += dataKey.toUpperCase();
            } else {
              // Insert the lowercase key value
              output.value += dataKey.toLowerCase();
            }
            // If shift is active, deactivate it
            if (shift) {
              shift = false;
              keyboard
                .querySelector('kbd[data-key="shift"]')
                .classList.remove("active");
            }
        }
      });
    }

    // Define an object to store the key values for each mode
    const keyValues = {
      normal: {
        "`": "`",
        1: "1",
        2: "2",
        3: "3",
        4: "4",
        5: "5",
        6: "6",
        7: "7",
        8: "8",
        9: "9",
        0: "0",
        "-": "-",
        "+": "+",
        q: "q",
        w: "w",
        e: "e",
        r: "r",
        t: "t",
        y: "y",
        u: "u",
        i: "i",
        o: "o",
        p: "p",
        "[": "[",
        "]": "]",
        "\": "\",
        a: "a",
        s: "s",
        d: "d",
        f: "f",
        g: "g",
        h: "h",
        j: "j",
        k: "k",
        l: "l",
        ";": ";",
        "'": "'",
        z: "z",
        x: "x",
        c: "c",
        v: "v",
        b: "b",
        n: "n",
        m: "m",
        ",": ",",
        ".": ".",
        "/": "/",
      },
      shift: {
        "`": "~",
        1: "!",
        2: "@",
        3: "#",
        4: "$",
        5: "%",
        6: "^",
        7: "&",
        8: "*",
        9: "(",
        0: ")",
        "-": "_",
        "+": "=",
        q: "Q",
        w: "W",
        e: "E",
        r: "R",
        t: "T",
        y: "Y",
        u: "U",
        i: "I",
        o: "O",
        p: "P",
        "[": "{",
        "]": "}",
        "\": "|",
        a: "A",
        s: "S",
        d: "D",
        f: "F",
        g: "G",
        h: "H",
        j: "J",
        k: "K",
        l: "L",
        ";": ":",
        "'": '"',
        z: "Z",
        x: "X",
        c: "C",
        v: "V",
        b: "B",
        n: "N",
        m: "M",
        ",": "<",
        ".": ">",
        "/": "?",
      },
      caps: {
        "`": "`",
        1: "1",
        2: "2",
        3: "3",
        4: "4",
        5: "5",
        6: "6",
        7: "7",
        8: "8",
        9: "9",
        0: "0",
        "-": "-",
        "+": "+",
        q: "Q",
        w: "W",
        e: "E",
        r: "R",
        t: "T",
        y: "Y",
        u: "U",
        i: "I",
        o: "O",
        p: "P",
        "[": "[",
        "]": "]",
        "\": "\",
        a: "A",
        s: "S",
        d: "D",
        f: "F",
        g: "G",
        h: "H",
        j: "J",
        k: "K",
        l: "L",
        ";": ";",
        "'": "'",
        z: "Z",
        x: "X",
        c: "C",
        v: "V",
        b: "B",
        n: "N",
        m: "M",
        ",": ",",
        ".": ".",
        "/": "/",
      },
    };

    // Define a function to update the key values
    function updateKeys() {
      // Loop through the keys
      for (let key of keys) {
        // Check the data-exclude attribute
        let exclude = key.getAttribute("data-exclude");
        if (exclude) {
          // Skip the key
          continue;
        }
        // Get the data-key attribute value
        let dataKey = key.getAttribute("data-key");
        // Check which mode is active
        if (shift) {
          // Set the key value to the shift mode value
          key.textContent = keyValues.shift[dataKey];
          key.dataset.key = keyValues.shift[dataKey];
        } else if (caps) {
          // Set the key value to the caps mode value
          key.textContent = keyValues.caps[dataKey];
          key.dataset.key = keyValues.caps[dataKey];
        } else {
          // Set the key value to the normal mode value
          key.textContent = keyValues.normal[dataKey];
          key.dataset.key = keyValues.normal[dataKey];
        }
      }
    }

    // Call the updateKeys function initially
    updateKeys();

    // Add a click event listener to the shift key
    keyboard
      .querySelector('kbd[data-key="shift"]')
      .addEventListener("click", function () {
        // Update the key values after toggling the shift mode
        updateKeys();
      });

    // Add a click event listener to all the keys besides the shift key, so that after one is pressed, shift is turned off
    for (let key of keys) {
      if (key !== keyboard.querySelector('kbd[data-key="shift"]')) {
        key.addEventListener("click", function () {
          shift = false;
          keyboard
            .querySelector('kbd[data-key="shift"]')
            .classList.remove("active");
          updateKeys();
        });
      }
    }

    // Add a click event listener to the caps lock key
    keyboard
      .querySelector('kbd[data-key="caps"]')
      .addEventListener("click", function () {
        // Update the key values after toggling the caps lock mode
        updateKeys();
      });
  </script>
</html>

https://jsfiddle.net/oxmzsrqe/

Here is the most simple version of the code that causes the error:

https://jsfiddle.net/yr8213bh/

By undefined, I mean that before clicking any keys, the key and code look like this:
Code before keys

After pressing some keys, it remains the same. Until I press the Shift key. Then, this happens:

Still looks OK

But now, after pressing shift, if I press a key again, I get this result:

Undefined error

This happens when pressing any key after shift.

I tried several things, among which were:

  • Using one escape character ().
  • Using multiple escape characters (\\).
  • Using HTML entities (\ and others)
  • Changing my JS code to handle undefined, convert data to a string, and many other things.

2

Answers


  1. You should use HTML entity for a backslash rather than literal :

    <kbd data-key="\">&#92;</kbd>
    
    Login or Signup to reply.
  2. Change the data-key attribute to "". You don’t need to escape it in HTML code. Only in javascript code.

    <kbd data-key=""></kbd>
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search