I’m trying to show/hide more info about names on click, but don’t know how to make it work of a single click.
I’m fetching JSON that has game related info and creating a div with JS like so:
fetch("thething.json")
.then(res => res.json())
.then(data =>{
games = data.map(game => {
const newDiv = document.createElement("div");
newDiv.className = "game-info";
newDiv.innerHTML = `
<p onclick="toggler()";>${game.Name}</p>
<div class="info">
<img src="${game.Thumbnail}">
<p>${game.Description}</p>
</div>
`;
document.body.appendChild(newDiv);
JSON itself has a bunch of info on games in structure like this:
[{"Name: gamename1,
"Thumbnail: https://imglocation,
"Description": This game is indeed a game
},
{"Name: gamename2,
"Thumbnail: https://imglocation2,
"Description": This game2 is indeed a game2
}
]
The toggler function is written like this:
function toggler(){
$('div.game-info').click(function(e){
$(this).children('.info').toggle();
});
}
It kinda works, but it takes one or more clicks to view the additional info. I know the problem is due to multiple onclick calls, but don’t know how to make it with a single click. I tried using jQuery without the toggler function, but then it opens info on all the names and not just the one which was clicked. So if someone could either tell me how to get rid of that secondary onclick or how to properly target the info which I clicked in the innerHTML section that’d be great!
2
Answers
The main issue in your code is because you’re nesting event handlers, ie. the native JS one and a jQuery one. This is causing odd behaviour where you need to click multiple times for the logic to have any effect. You can avoid the issue by just using one event handler to hide/show the element on succesive clicks:
Also note that it’s not good practice to use
onclick
attriutes. Event handlers should be bound unobtrusively in JS, not in HTML.Here’s a working example with the above changes applied:
You’re
toggle()
function is what is establishing the click event. This is why you have to click once before anything happens, there is no event listener before that. Also every time you click it, it will add a new event handler, which is why you’re getting odd repeated behaviors. This is one reason why it’s consider bad practice to put javascript in the html these days, keep the javascript between the<script>
tags.Also
$('div.game-info')
is selecting alldiv
s with a class ofgame-info
, which is probably why it’s toggling everything. You probably want something like$('div').on('click', '.game-info')
The .on() method allows you to provide a secondselector
argument, which then in the handler functionthis
refers to the specific element that triggered the event, rather than all of them.If your project is using jQuery, might as well use it! Here’s what that might look like:
$.getJSON() – assuming your data source returns valid JSON, the first argument of the
.done()
method will be a parsed JSON object, no extra steps. And if the source isn’t valid, you can handle that in the.fail()
method.Next, rather than mutating the DOM for every single game, you could create one giant html string and only have to mutate the DOM once. Then, again, you can put the event handler on some parent of the dynamically added html (
body
in this case), and use the selector argument to select a specific element that should handle the event.