简体   繁体   中英

innerHTML creates a new element rather than replacing the innerHTML of the targeted element

I am trying to replace the innerHTML of an <i> element but it seems like an additional <i> element gets created instead of having the innerHTML get replaced and rewritten. The <i> element contains a class for a library called zmdi. My goal is to change the class for this element so that I can change the image when it is clicked.

Here is the element with the HTML I am trying to change: <i class="zmdi zmdi-mic zmdi-hc-2x" id = "micButton"></i>

I am trying to change it to: <i class="zmdi zmdi-mic-off zmdi-hc-2x" id = "micButton"></i>

I have tried several things:

1. When logging, I noticed that before the element is clicked, it's innerHTML seems to have no value. After being clicked, it logs the innerHTML that I set it to which is:

<i class="zmdi zmdi-mic-off zmdi-hc-2x" id = "micButton"></i>

I am not sure if this is related to problem, but it seems odd, especially because I call the js file at the bottom of the HTML file, so there shouldn't be an issue trying to call the element before it is initialized.

  1. I tried changing the innerHTML of a test div. The test div is as follows: <div class="blue" id="test">test div</div> and when clicked it's innerHTML is changed to <div class="red" id="test">test div</div> It worked as expected, however in the log before the div is clicked, it's value is only test div while I would have expected it to have all the innerHTML logged as well. Additionally, not sure why, but this one does successfully replace it's innerHTML with the new innerHTML while the other one does not.

Here is a codepen that shows the problem: https://codepen.io/mso122591/pen/JQWMYX

Here is the relevant HTML (Note: I am using pug)

doctype html
html(lang='en')
  head
    title= title
    meta(charset='utf-8')
    meta(name='viewport', content='width=device-width, initial-scale=1')
    <script src='https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js'></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/material-design-iconic-font/2.2.0/css/material-design-iconic-font.min.css">
script.
      var room="#{room}";
link(rel='stylesheet', href='/style.css')
body
<h1>#{title} </h1>
<div class="blue" id="test">test div</div>
<div class= "menu">
 <div class= "buttons-container">
     <div class= "single-button-container">
        <i class="zmdi zmdi-mic zmdi-hc-2x" id = "micButton"></i>
     </div>
 </div>
<script src="/gameChat.js"></script>

Here is the relevant JS:

let micButton= document.getElementById('micButton');
 //Test Div
let test=document.getElementById('test');

//Onclick for element I am trying to change
micButton.addEventListener("click", function(event){
    console.log("before click",micButton.innerHTML);
    micButton.innerHTML= '<i class="zmdi zmdi-mic-off zmdi-hc-2x" id = 
"micButton"></i>';
    console.log("after click",micButton.innerHTML);
  });


//Onclick for the Test Div
    test.addEventListener("click", function(event){
    console.log(" test div before click",test.innerHTML);
    test.innerHTML= '<div class="red" id="test">test div</div>';
   console.log("test div after click",test.innerHTML);
  });

I think this should be enough to show the problem, but please let me know if more code is needed.

I ultimately did get this to work by using .className instead of .innerHTMl and setting the class that way (which perhaps is a better way do it anyway?) but it would be great to understand what the issue is here.

Try to use classList.add / classList.remove instead of innerHTML. Something like that:

micButton.addEventListener("click", function(e){
    micButton.classList.add('new-class');
    micButton.classList.remove('old-class');
  });

In regards to the actual problem - innerHTML is the content/child elements. So it should not contain the element itself. In this case innerHTML is not the correct solution as there is no content. The suggested class add/remove is a better solution.

Usually innerHTML is used to replace the actual text that the tag contains. When using innerHTML and setting it to <i class="zmdi zmdi-mic-off zmdi-hc-2x" id = "micButton"></i> what you're asking for it to do is take the empty string currently in <i> and add a whole new <i> tag. This is demonstrated in the first button click. You will see that the text disappears because it's replaced with a tag.

The current modern way of replacing a class is by using classList . The second method demonstrates how to use it.

 let failButton = document.getElementById('failButton'); let micButton= document.getElementById('micButton'); //Onclick for element adding tag into tag failButton.addEventListener("click", function(event){ console.log("before click",failButton.innerHTML); failButton.innerHTML= '<i class="zmdi zmdi-mic-off zmdi-hc-2x" id = "failButton"></i>'; console.log("after click", failButton.innerHTML); }); //Onclick for element that works micButton.addEventListener("click", function(event){ document.getElementById("micButton").classList.add('zmdi-mic-off'); document.getElementById("micButton").classList.remove('zmdi-mic'); console.log(document.getElementById("micButton")); }); 
 <div class= "menu"> <div class= "buttons-container"> <div class= "single-button-container"> <i class="zmdi zmdi-mic zmdi-hc-2x" id = "failButton">Replace this with tag</i> </div> </div> <div class= "menu"> <div class= "buttons-container"> <div class= "single-button-container"> <i class="zmdi zmdi-mic zmdi-hc-2x" id = "micButton">Replace class in tag</i> </div> </div> 

You can shorten up all this code by using JQuery toggleClass() :

https://jsfiddle.net/DIRTY_SMITH/vz04m3ph/43/

$("#test").click(function(){
  $(this).toggleClass( "red" )
});
$(".single-button-container > i").click(function(){
  $(this).toggleClass("zmdi-mic")
  $(this).toggleClass("zmdi-mic-off")
});

Note: The toggleClass(.red) is working because you have .red under .blue in your CSS. The CSS will apply the last style to the element. The element is starting out with only the class .blue then toggling .red on and off.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM