Kiwa
Kiwa

Reputation: 215

Javascript copy to clipboard function messages doesn't work if used twice

I have this code I edited from w3tutorials. When you click on the Hello World button, it says Copied: Welcome Message. However if you click John button, it doesn't say anything. it copies to the clipboard, but doesn't show the "Copied" message.

function myFunction(classID, IDName) {
  var copyText = document.getElementById(classID);
  copyText.select();
  document.execCommand("copy");
  
  var tooltip = document.getElementById("myTooltip");
  tooltip.innerHTML = "Copied: " + IDName;
}

function outFunc() {
  var tooltip = document.getElementById("myTooltip");
  tooltip.innerHTML = "Copy to clipboard";
}
body {
  margin: 50px;
}
.tooltip {
  position: relative;
  display: inline-block;
}

.tooltip .tooltiptext {
  visibility: hidden;
  width: 140px;
  background-color: #555;
  color: #fff;
  text-align: center;
  border-radius: 6px;
  padding: 5px;
  position: absolute;
  z-index: 1;
  bottom: 150%;
  left: 50%;
  margin-left: -75px;
  opacity: 0;
  transition: opacity 0.3s;
}

.tooltip .tooltiptext::after {
  content: "";
  position: absolute;
  top: 100%;
  left: 50%;
  margin-left: -5px;
  border-width: 5px;
  border-style: solid;
  border-color: #555 transparent transparent transparent;
}

.tooltip:hover .tooltiptext {
  visibility: visible;
  opacity: 1;
}
<body>
  <input type="text" value="Hello World" id="welcome">

  <div class="tooltip">
  <button onclick="myFunction('welcome', 'Welcome Message')" onmouseout="outFunc()">
    <span class="tooltiptext" id="myTooltip">Copy to clipboard</span>
    Copy text
    </button>
  </div>
  
  <br>
  
  <input type="text" value="John" id="fname">

  <div class="tooltip">
  <button onclick="myFunction('fname', 'First Name')" onmouseout="outFunc()">
    <span class="tooltiptext" id="myTooltip">Copy to clipboard</span>
    Copy text
    </button>
  </div>
</body>

Upvotes: 1

Views: 1047

Answers (3)

T.J. Crowder
T.J. Crowder

Reputation: 1074495

ids must be unique. You probably don't want to use any IDs in this code at all. Instead, put each structure in a div so you can relate the elements to each other structurally rather than with IDs (it also eliminates the need for that <br>). For instance, with this structure:

<div class="group">
  <input type="text" value="Hello World">

  <div class="tooltip">
  <button onclick="myFunction(this, 'Welcome Message')" onmouseout="outFunc(this)">
    <span class="tooltiptext">Copy to clipboard</span>
    Copy text
    </button>
  </div>
</div>

Notice that this is passed into the handler functions (really, we should be using modern event handling, but I'm trying not to change too much in one go). this will be the element that function is attached to. Then in the code, it's easy to find the various other elements in that group:

function myFunction(button, IDName) {
  var input = button.closest(".group").querySelector("input");
  input.select();
  document.execCommand("copy");

  var tooltip = button.querySelector(".tooltiptext");
  tooltip.innerHTML = "Copied: " + IDName;
}

function outFunc(button) {
  var tooltip = button.querySelector(".tooltiptext");
  tooltip.innerHTML = "Copy to clipboard";
}

Then of course, as always, we can factor out common code to utility functions:

function myFunction(button, IDName) {
  var input = button.closest(".group").querySelector("input");
  input.select();
  document.execCommand("copy");
  setTooltipForButton(button, "Copied: " + IDName);
}

function outFunc(button) {
  setTooltipForButton(button, "Copy to clipboard");
}

function setTooltipForButton(button, text) {
  button.querySelector(".tooltiptext").innerHTML = text;
}

I should note that that uses Element#closest, which is supported by modern browsers but not in some older ones. You can use a polyfill for older browsers to add it, though.

Live Example:

function myFunction(button, IDName) {
  var input = button.closest(".group").querySelector("input");
  input.select();
  document.execCommand("copy");
  setTooltipForButton(button, "Copied: " + IDName);
}

function outFunc(button) {
  setTooltipForButton(button, "Copy to clipboard");
}

function setTooltipForButton(button, text) {
  button.querySelector(".tooltiptext").innerHTML = text;
}
body {
  margin: 50px;
}
.tooltip {
  position: relative;
  display: inline-block;
}

.tooltip .tooltiptext {
  visibility: hidden;
  width: 140px;
  background-color: #555;
  color: #fff;
  text-align: center;
  border-radius: 6px;
  padding: 5px;
  position: absolute;
  z-index: 1;
  bottom: 150%;
  left: 50%;
  margin-left: -75px;
  opacity: 0;
  transition: opacity 0.3s;
}

.tooltip .tooltiptext::after {
  content: "";
  position: absolute;
  top: 100%;
  left: 50%;
  margin-left: -5px;
  border-width: 5px;
  border-style: solid;
  border-color: #555 transparent transparent transparent;
}

.tooltip:hover .tooltiptext {
  visibility: visible;
  opacity: 1;
}
<div class="group">
  <input type="text" value="Hello World">

  <div class="tooltip">
  <button onclick="myFunction(this, 'Welcome Message')" onmouseout="outFunc(this)">
    <span class="tooltiptext">Copy to clipboard</span>
    Copy text
    </button>
  </div>
</div>

<div class="group">  
  <input type="text" value="John">

  <div class="tooltip">
  <button onclick="myFunction(this, 'First Name')" onmouseout="outFunc(this)">
    <span class="tooltiptext">Copy to clipboard</span>
    Copy text
    </button>
  </div>
</div>

Of course, if you need the ids for something else, it's okay to include them, they just need to be unique on the page.

Upvotes: 3

souzan
souzan

Reputation: 276

Because of this line: var tooltip = document.getElementById("myTooltip"); , when you click the second button, it's the text in the first tooltip that changes because you can't use the same ID twice.

I edited your code to select the tooltip using the class name and replace each tooltip's text whenever the button is clicked.

Check this codepen: https://codepen.io/anon/pen/YBEJjB

Upvotes: 0

Carlo77PV
Carlo77PV

Reputation: 106

You can't use the same ID more than one time.
You can add a counter or a pointer to make the ID unique.

function myFunction(classID, IDName) {
  var copyText = document.getElementById(classID);
  copyText.select();
  document.execCommand("copy");
  
  var tooltip = document.getElementById("myTooltip-" + classID); //modify here
  tooltip.innerHTML = "Copied: " + IDName;
}

function outFunc(classID) {
  var tooltip = document.getElementById("myTooltip-" + classID);//modify here
  tooltip.innerHTML = "Copy to clipboard";
}
body {
  margin: 50px;
}
.tooltip {
  position: relative;
  display: inline-block;
}

.tooltip .tooltiptext {
  visibility: hidden;
  width: 140px;
  background-color: #555;
  color: #fff;
  text-align: center;
  border-radius: 6px;
  padding: 5px;
  position: absolute;
  z-index: 1;
  bottom: 150%;
  left: 50%;
  margin-left: -75px;
  opacity: 0;
  transition: opacity 0.3s;
}

.tooltip .tooltiptext::after {
  content: "";
  position: absolute;
  top: 100%;
  left: 50%;
  margin-left: -5px;
  border-width: 5px;
  border-style: solid;
  border-color: #555 transparent transparent transparent;
}

.tooltip:hover .tooltiptext {
  visibility: visible;
  opacity: 1;
}
<body>
  <input type="text" value="Hello World" id="welcome">

  <div class="tooltip">
  <button onclick="myFunction('welcome', 'Welcome Message')" onmouseout="outFunc('welcome')"><!--modify here-->
    <span class="tooltiptext" id="myTooltip-welcome"><!--modify here-->Copy to clipboard</span>
    Copy text
    </button>
  </div>
  
  <br>
  
  <input type="text" value="John" id="fname">

  <div class="tooltip">
  <button onclick="myFunction('fname', 'First Name')" onmouseout="outFunc('welcome')"><!--modify here-->
    <span class="tooltiptext" id="myTooltip-fname"><!--modify here-->Copy to clipboard</span>
    Copy text
    </button>
  </div>
</body>

Upvotes: 2

Related Questions