admin管理员组

文章数量:1415100

I have three HTML buttons with ids and classes. Two of them also hold data attributes.

The data attributes are for the element they should change the style display property for.

The basic idea is to show or hide paragraph elements. I am trying to reduce repetitive code by using querySelectors and for loops instead of having multiple event listeners. I am stuck at writing the function that starts on line 31 of the codepen. I have tried: document.querySelector(classbtns[i].getAttribute('data-value')).style.display = "inline"; and I am getting: TypeError: document.querySelector(...) is null

I have retained and mented out earlier code-blocks to help give you an idea of what I am trying to do.

Please see my code and link to the codepen below:

html:

 <p id="toy-pictures-latest" class="panel">Latest Toy Pictures</p><br>
         <p id="toy-pictures-greatest" class="panel">Greatest Toy Pictures</p>

Toy Pictures
<button type="button" id="btnlatest" data-value="toy-pictures-latest" class="buttons">Latest</button>
<button type="button" id="btngreatest" data-value="toy-pictures-greatest class="buttons">Greatest</button></details></li>
<button type="button" id="clear-btn">Clear</button>

css:

 #toy-pictures-latest.panel{
    display: inline;
}

#toy-pictures-greatest.panel{
        display: inline;
}

js:

/*function fgreatest() {
   document.getElementById('toy-pictures-greatest').style.display = "inline";
   }*/

//The following function clears the p elements in class "panel" by changing the display value in css

function clearall()
{
var panels = document.querySelectorAll('.panel'), i;  
console.log("exe");  
for (i = 0; i < panels.length; ++i) {
  panels[i].style.display = "none";
}

}  

//This is the previous version of the querySelector.
//It required a new function for each <p> element id 

/*const classbtns = document.querySelectorAll(".buttons");

 for (let i = 0; i < classbtns.length; i++) {
     classbtns[i].addEventListener("click", fgreatest);
 }*/

//This is the attempt to grab the name of the element
//from the html data value property and change the css //style display to inline

 const classbtns = document.querySelectorAll(".buttons");
 
  for (let i = 0; i < classbtns.length; i++) {
     classbtns[i].addEventListener("click", function() {
     
     document.querySelector(classbtns[i].getAttribute('data-value')).style.display = "inline";
      });
  }

document.getElementById('clear-btn').addEventListener("click", clearall);

codepen

I have three HTML buttons with ids and classes. Two of them also hold data attributes.

The data attributes are for the element they should change the style display property for.

The basic idea is to show or hide paragraph elements. I am trying to reduce repetitive code by using querySelectors and for loops instead of having multiple event listeners. I am stuck at writing the function that starts on line 31 of the codepen. I have tried: document.querySelector(classbtns[i].getAttribute('data-value')).style.display = "inline"; and I am getting: TypeError: document.querySelector(...) is null

I have retained and mented out earlier code-blocks to help give you an idea of what I am trying to do.

Please see my code and link to the codepen below:

html:

 <p id="toy-pictures-latest" class="panel">Latest Toy Pictures</p><br>
         <p id="toy-pictures-greatest" class="panel">Greatest Toy Pictures</p>

Toy Pictures
<button type="button" id="btnlatest" data-value="toy-pictures-latest" class="buttons">Latest</button>
<button type="button" id="btngreatest" data-value="toy-pictures-greatest class="buttons">Greatest</button></details></li>
<button type="button" id="clear-btn">Clear</button>

css:

 #toy-pictures-latest.panel{
    display: inline;
}

#toy-pictures-greatest.panel{
        display: inline;
}

js:

/*function fgreatest() {
   document.getElementById('toy-pictures-greatest').style.display = "inline";
   }*/

//The following function clears the p elements in class "panel" by changing the display value in css

function clearall()
{
var panels = document.querySelectorAll('.panel'), i;  
console.log("exe");  
for (i = 0; i < panels.length; ++i) {
  panels[i].style.display = "none";
}

}  

//This is the previous version of the querySelector.
//It required a new function for each <p> element id 

/*const classbtns = document.querySelectorAll(".buttons");

 for (let i = 0; i < classbtns.length; i++) {
     classbtns[i].addEventListener("click", fgreatest);
 }*/

//This is the attempt to grab the name of the element
//from the html data value property and change the css //style display to inline

 const classbtns = document.querySelectorAll(".buttons");
 
  for (let i = 0; i < classbtns.length; i++) {
     classbtns[i].addEventListener("click", function() {
     
     document.querySelector(classbtns[i].getAttribute('data-value')).style.display = "inline";
      });
  }

document.getElementById('clear-btn').addEventListener("click", clearall);

codepen

Share Improve this question edited Sep 13, 2020 at 6:53 Always Helping 14.6k4 gold badges15 silver badges30 bronze badges asked Sep 13, 2020 at 5:41 castoncaston 1591 silver badge16 bronze badges
Add a ment  | 

4 Answers 4

Reset to default 3

I found two issues:

  1. In HTML, data-value tag for button "btngreatest" is missing end quote.

    <button type="button" id="btngreatest" data-value="toy-pictures-greatest class="buttons">

  2. Since you want to select panels by ID, you should prefix with '#'

    document.querySelector('#'+ classbtns[i].getAttribute('data-value')).style.display = "inline";

When selecting an element by Id with document.querySelector you need to preface with "#" so that would be:

document.querySelector('#' + classbtns[i].getAttribute('data-value')).style.display = "inline";
      });

But then you might as well just use

document.getElementById(classbtns[i].getAttribute('data-value')).style.display = "inline";

Just as an additive to the solutions already it may be worth taking into consideration the good old MDN on getting the data attribute:

[...], but the standard defines a simpler way: a DOMStringmap you can read out via a dataset property. https://developer.mozilla/en-US/docs/Learn/HTML/Howto/Use_data_attributes

I personally would also go for the target of of the event. Something like:

const attachListener = btn => btn.addEventListener('click', (e) => document.getElementById(e.target.dataset.value).style.display = 'inline';

clsBtns.forEach(attachListener);

Here is a more current and simplified clean approach by using forEach method and targeting the actual element we have clicked on using event.target method

Event.target will ensure you are targeting the correct element to get its data-value - This approach is better if you have alot of buttons and nested inside each other.

You can also use newly dataset approach as well instead of using the getAtribute method

Using data.set

 document.querySelector("#" + e.target.dataset.value).style.display = "inline";

Live Demo:

function clearall() {
  var panels = document.querySelectorAll('.panel')
  panels.forEach(function(el) {
    el.style.display = "none";
  });
}

const classbtns = document.querySelectorAll(".buttons");
classbtns.forEach(function(btn) {
  btn.addEventListener("click", function(e) {
    document.querySelector("#" + e.target.getAttribute('data-value')).style.display = "inline";
  })
})

//clear al;
document.getElementById('clear-btn').addEventListener("click", clearall);
#toy-pictures-latest.panel {
  display: none;
}

#toy-pictures-greatest.panel {
  display: none;
}
<p id="toy-pictures-latest" class="panel">Latest Toy Pictures</p><br>
<p id="toy-pictures-greatest" class="panel">Greatest Toy Pictures</p>

<br>
Toy Pictures
<button type="button" id="btnlatest" data-value="toy-pictures-latest" class="buttons">Latest</button>

<button type="button" id="btngreatest" data-value="toy-pictures-greatest" class="buttons">Greatest</button>

<button type="button" id="clear-btn">Clear</button>

本文标签: javascriptParsing HTML5 dataattribute to documentquerySelectorStack Overflow