Home > Blockchain >  Using “this” to select an element’s innerText
Using “this” to select an element’s innerText

Time:01-04

I’m a beginner, so I apologize if I’m missing something obvious.

I’m trying to write a simple web app. When you type text into a textarea and click a button, a “card” (div) is created with that textarea’s value as its innerText. When you click on a card, its innerText is then copied to the clipboard.

It works when I write out the function this way:

el.setAttribute(
      "onclick",
      "console.log(navigator.clipboard.writeText(this.innerText));"
    );

But if I write out the function separately and call it when setting the attribute, undefined is copied to the keyboard:

el.setAttribute("onclick", "copyText()");

I’d stick with the first, working option, except for two things:

  1. Primarily I’m just trying to learn, so avoiding difficulties because I don’t understand them doesn’t really make sense.
  2. I want to add more lines of code to the copyText() function so that it works on mobile devices, too. Can I even do that the first way?

Here’s my code in full:

const app = document.getElementById("app");

function createCard() {
  let input = document.getElementById("textarea").value;
  if (input == "") {
    console.log("You must enter text to create a card.");
  } else {
    const el = document.createElement("div");
    el.innerText = document.getElementById("textarea").value;
    el.setAttribute("class", "item card");
    el.setAttribute("onclick", "copyText()");
    app.appendChild(el);
    document.getElementById("textarea").value = "";
  }
}

function copyText() {
  navigator.clipboard.writeText(this.innerText);
}

I expected it to work exactly the same as the following, but it doesn’t. It returns undefined.

const app = document.getElementById("app");

function createCard() {
  let input = document.getElementById("textarea").value;
  console.log(input);
  if (input == "") {
    console.log("You must enter text to create a card.");
  } else {
    const el = document.createElement("div");
    el.setAttribute("class", "item card");
    el.setAttribute(
      "onclick",
      "console.log(navigator.clipboard.writeText(this.innerText));"
    );
    el.innerText = document.getElementById("textarea").value;
    app.appendChild(el);
    document.getElementById("textarea").value = "";
  }
}

I suspect it’s an issue with “this” and scope, but I can’t figure it out. Sorry again—I know this is very much a beginner’s question. Thanks for your help.

CodePudding user response:

Calling copyText() calls it without a this context. You would need to use

el.setAttribute("onclick", "copyText.call(this)");
// ideally also pass the event object:
el.setAttribute("onclick", "copyText.call(this, event)");

However, the best practice is to install an event handler function instead of using the onclick attribute, so you should do

el.onclick = copyText;
// or
el.addEventListener("click", copyText);

Notice these refer to the copyText function that is in scope, it doesn't need to be a global variable.

const input = document.getElementById("textarea");
const app = document.getElementById("app");
function createCard() {
  console.log(input.value);
  if (!input.value) {
    console.log("You must enter text to create a card.");
  } else {
    const el = document.createElement("div");
    el.className = "item card";
    el.onclick = function() {
      console.log(navigator.clipboard.writeText(this.textContent));
    };
    el.textContent = input.value;
    app.appendChild(el);
    input.value = "";
  }
}
  • Related