How to use jQuery toggle method dynamically? - javascript

In my project, there are so many jQuery toggles needed for changing text and icons. Now I’m doing that using:
$("#id1").click(function () {
//Code to toggle display and change icon and text
});
$("#id2").click(function () {
//Same Code to toggle display and change icon and text as above except change in id
});
The problem is that I got so many to toggle, the code is quite long but all I change for each one is the id. So I was wondering if there is any way to make this simple.
Below is a sample pic. I got so many more in single page.

There are two issues here.
How to run the same action on multiple elements
How to know which element you've clicked so that you can run a relevant action on it. (most of the existing answers skip this part).
The first is to use a class for each of the elements you want to click, rather than wire up via an id. You can use a selector similar to [id^=id] but it's just cleaner to use a class.
<div id="id1" class="toggler">...
which allows you to:
$(".toggler").click(function() ...
the second is it associate the clickable with the item you want to toggle. There are many ways to do this, my preferred option is to associate them with data- attributes, eg:
<div class="togger" data-toggle="#toggle1">...
which allows you to:
$(".toggler").click(function() {
$($(this).data("toggle")).toggle();
});
The key here is that this is the element being clicked, so you can do anything else with this such as show/hide an icon inside or change colour.
Example:
$(".toggler").click(function() {
$($(this).data("toggle")).toggle();
$(this).toggleClass("toggled");
});
.toggler { cursor: pointer }
.toggled { background-color: green }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="toggler" data-toggle="#t1">T1</div>
<div class="toggler" data-toggle="#t2">T2</div>
<div class="toggler" data-toggle="#t3">T3</div>
<hr/>
<div id="t1" style='display:none;'>T1 content</div>
<div id="t2" style='display:none;'>T2 content</div>
<div id="t3" style='display:none;'>T3 content</div>

Oh,Can you use a class instead of id?
<ul>
<li class="idx">A</li>
<li class="idx">B</li>
<li class="idx">C</li>
</ul>
$(".idx").click(function(e){
//Code to toggle display and change icon and text
let target = e.target;
//You can do all what you want just base on the `target`;
});

You can store the queries in an array, and iterate over them to perform the same JQuery operation on all of them
let ids = ["#id1", "#id2", "#id3", "#randomID"]
ids.forEach((id) => {
console.log($(id).html())
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul>
<li id="id1">A</li>
<li id="id2">B</li>
<li id="id3">C</li>
<li id="randomID">D</li>
</ul>
Or (If like your example) and all of the id's are actually id1, id2, id3, ... etc.
let id = "id";
let n = 3; //amount of id's
for (let i = 1; i <= n; i++) {
console.log($("#" + id + i).html())
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul>
<li id="id1">A</li>
<li id="id2">B</li>
<li id="id3">C</li>
</ul>

You can try the below code.
var num = $("#myList").find("li").length;
console.log(num)
for(i=0;i<num;i++){
$("#id"+ i).click(function(e){
let target = e.target;
});
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<ul id="myList">
<li id="id1">A</li>
<li id="id2">B</li>
<li id="id3">C</li>
</ul>

Related

I want to change certain names in my UL using a button

I want to change 9 of the names in the UL to a red font using a on click button, while the other 3 names remain in a black font. And I want a button to reset the red fonts back to their original font. Can anyone help?
var title = document.getElementById("title");
var buttons = document.getElementsByClassName("btn");
var buttons = document.getElementsByClassName("btn2");
for (var btnIndex = 0; btnIndex < buttons.length; btnIndex++) {
buttons[btnIndex].onclick = function() {
title.style.color = this.getAttribute('data-color');
}
} else {
title1.style.color = this.getAttribute('data-color');
}
<ul>
<li id="title">John</li>
<li id="title">Jack</li>
<li id="title">Joe</li>
<li id="title1">Jim</li>
<li id="title">David</li>
<li id="title">Sam</li>
<li id="title1">Jay</li>
<li id="title">Frank</li>
<li id="title">Tim</li>
<li id="title">Zack</li>
<li id="title">Lewis</li>
<li id="title1">Danny</li>
<button class="btn" data-color="red">Change 9 names to red</button>
<button class="btn2" data-color="black">Reset</button>
</ul>
There are a couple of problems with your markup, which I'll address below, but to answer your actual question, you can do something like this:
// get references to the buttons
const button1 = document.querySelector('.btn');
const button2 = document.querySelector('.btn2');
// declare a function that adds the class 'red' to items matching the given selector
const select = selector => {
[...document.querySelectorAll(selector)].forEach(
element => element.classList.add('red')
);
}
// declare a function that removes the given class from all elements that currently have it
const deselect = className => {
[...document.querySelectorAll('.' + className)].forEach(
element => element.classList.remove(className)
);
}
// add a click handler to the button that invokes the
// select function above for items whose class includes 'title'
button1.addEventListener('click', () => select('.title'));
// add a click handler to the second button that removes the 'red' class from all items
button2.addEventListener('click', () => deselect('red'));
.red {
color: red;
}
<ul>
<li class="title">John</li>
<li class="title">Jack</li>
<li class="title">Joe</li>
<li class="title1">Jim</li>
<li class="title">David</li>
<li class="title">Sam</li>
<li class="title1">Jay</li>
<li class="title">Frank</li>
<li class="title">Tim</li>
<li class="title">Zack</li>
<li class="title">Lewis</li>
<li class="title1">Danny</li>
</ul>
<button class="btn" data-color="red">Change 9 names to red</button>
<button class="btn2" data-color="black">Reset</button>
a more efficient solution
This may not suit your needs, but if you just want to change the color of title items you could toggle a class on the <ul> and apply a css rule:
// get references to the button and ul
const button = document.querySelector('.btn');
const ul = document.querySelector('ul');
// toggle a class on the ul
button.addEventListener('click', () => ul.classList.toggle('red'));
/*
color 'title' items when the
ul has the 'red' class
*/
ul.red .title {
color: red;
}
<ul>
<li class="title">John</li>
<li class="title">Jack</li>
<li class="title">Joe</li>
<li class="title1">Jim</li>
<li class="title">David</li>
<li class="title">Sam</li>
<li class="title1">Jay</li>
<li class="title">Frank</li>
<li class="title">Tim</li>
<li class="title">Zack</li>
<li class="title">Lewis</li>
<li class="title1">Danny</li>
</ul>
<button class="btn">Toggle 'title' items to red</button>
markup issues
id attributes must be unique within a document. if you need to attach the same identifier to multiple elements use class instead.
<button> cannot be a child of <ul>.
First, id values must be unique, so you should be using class to
organize the similar <li> elements and use id to uniquely
identify the two buttons.
Also, the only elements that can be a child of a <ul> are <li>,
<script> and <template> elements, not <button>, so the buttons
have to be moved out of the ul.
From there, it's just a matter of setting the two buttons click handlers to the same event handler that loops over the li elements with the given class (not the buttons as you are trying to do) and adds or removes a pre-made class to the list depending on which button was clicked.
// test.js contents
document.getElementById("btn").addEventListener("click", changeColor);
document.getElementById("btn2").addEventListener("click", changeColor);
let items = document.querySelectorAll(".title");
function changeColor(event){
items.forEach(function(item){
// Figure out which button got us here
if(event.target.id === "btn"){
item.classList.add("red"); // Add red
} else {
item.classList.remove("red"); // Remove red
}
});
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Change the Certain Font Color with JavaScript</title>
<style>
.red {color:red;}
</style>
</head>
<body>
<ul>
<li class="title">John</li>
<li class="title">Jack</li>
<li class="title">Joe</li>
<li class="title1">Jim</li>
<li class="title">David</li>
<li class="title">Sam</li>
<li class="title1">Jay</li>
<li class="title">Frank</li>
<li class="title">Tim</li>
<li class="title">Zack</li>
<li class="title">Lewis</li>
<li class="title1">Danny</li>
</ul>
<button id="btn">Change 9 names to red</button>
<button id="btn2">Reset</button>
<script src="test.js"></script>
</body>
</html>
Additional notes:
You'll want to stay away from using .getElementsByClassName().
Rather than looping with counter indexes, it's much simpler to use
the Array.forEach() method on the collection returned from .querySelectorAll().
You should avoid using inline styles whenever possible as they are the hardest to override and to maintain. Instead, add, remove, or toggle the use of CSS classes with the .classList API, which is much simpler to use.

Only show certain <div> if there's a certain element on the page

I'm trying to get the company I'm at a Help Centre set up, using Zendesk.
I've managed to implement a sidenav, but I'm struggling to make it show different anchor links depending on the category of the Help Centre the user is on. Zendesk only allows you to edit the HTML of the category page template, and I'm unable to dynamically load in the links.
Can anyone please advise on how to show DIV_1, only if the page contains <li title="Using ProductName">? I've searched but can't seem to find anything relevant.
From there I'll do the same for the other sections in the same way (e.g. only show DIV_2 if the page contains <li title="Developer Portal".
For reference, I have access to the category's HTML template, the CSS and JS.
Thanks in advance!
<div class="container">
<nav class="sub-nav">
<ol class="breadcrumbs">
<li title="Help Centre">
Help Centre
</li>
<li title="Using ProductName">
Using ProductName
</li>
</ol>
<div id="DIV_1">
<ul id="UL_2">
<li id="LI_1">
Admin and Settings
</li>
<li id="LI_1">
Getting Started
</li>
<li id="LI_1">
Content Types and Sources
</li>
<li id="LI_1">
Content Management
</li>
<li id="LI_1">
Content Publishing
</li>
<li id="LI_1">
Apps
</li>
<li id="LI_1">
Analytics
</li>
<li id="LI_1">
Troubleshooting
</li>
</ul>
</div>
</div>
</div>
You can use the built-in DOM query methods to accomplish this. In this case, you'd want to combine an if condition with the query, something like so:
if (document.querySelector('li[title="Using ProductName"]')) {
// make #DIV_1 visible however you please here
document.querySelector('#DIV_1').display = 'block';
}
If the li with the title Using ProductName does not exist, #DIV_1 will stay invisible; if it does, it will be shown.
You can do a quick for loop check:
var items = document.getElementsByTagName('li');
for (var i = 0; i < items.length; i++) {
if (items[i].title == titleToCheckFor) { showElement(); }
}
You can fill in titleToCheckFor with the title you're looking for ("Using _____") and the showElement function would display the div, or you could just show the div right in the loop.
Using DOM query method querySelector you can search the target element, by default we set all div's hidden, and then we show only the required.
<style>
.module {
display:none;
}
</style>
<script>
// by default we show MODULE A else show module B
var module = "DIV_1";
if (document.querySelector('li[title="Developer Portal"]')) {
module = "DIV_2";
}
// we show the respective DIV
document.querySelector('.' + module).display = 'block';
</script>
<div class="module DIV_1" id="DIV_1">
...
</div>
<div class="module DIV_2" id="DIV_2">
....
</div>
You can achieve this via CSS classes.
SOLUTION 1:
This being the sample HTML:
<div id="Div_1" class="menu-div using-productname">
</div>
<div id="Div_2" class="menu-div help-centre">
</div>
<div id="Div_3" class="menu-div other-tab">
</div>
Now you should setup your css like:
.menu-div {
display: none;
}
So all menu divs are hidden by default when the page loads
Now when you move to some tab suppose "Using ProductName", all you need to do is
var title = "Using ProductName"; //Get the title
var className = title.split(" ").join("-").toLowerCase(); //Convert it to the correct class which matches with your Divs in the menu
document.querySelector(".menu-div").style.display = "none"; //Set all menu divs to hidden
document.querySelector("." + className).style.display = "block"; //Show the desired menu div
SOLUTION 2:
This being the sample HTML:
<div class="parent-div">
<div id="Div_1" class="menu-div">
</div>
<div id="Div_2" class="menu-div">
</div>
<div id="Div_3" class="menu-div">
</div>
Now you should setup your css like:
.parent-div .menu-div {
display: none;
}
.parent-div.using-productname #Div_1 {
display: block;
}
.parent-div.help-centre #Div_2 {
display: block;
}
.parent-div.other-tab #Div_3 {
display: block;
}
Now when you move to some tab suppose "Using ProductName", all you need to do is
var title = "Using ProductName"; //Get the title
var className = title.split(" ").join("-").toLowerCase(); //Convert it to the correct class which you will add to the parent
document.querySelector(".parent-div").className = "parent-div " + className; //Set the parent div class to the className - the css will take care of the rest!
NOTE - Also you should use different ids on your different LIs and A tags.
You can use jQuery in Zendesk Help Centers so
var test = $('.breadcrumbs').children(':contains(amy)')
if(test.length > 0) {
do something here like
$('#LI_1').hide();
}
It's kind of simple brute force, but it works.

JS hiding a div while targeting anchor

I have multiple divs (class="profile") wich are hidden by default. Each div is only shown when targeted. I want all divs with class="employeeul" to be hidden when one of the profile divs is targeted. I don't get this working with css, does anyone know why? A JS solution is good as well. (I think I can't use something like onclick, because the divs must hide when the anchors are accessed from other sites.)
This is my code (I removed the divs content):
<div class="narrow_content">
<div class="profile" id="m_empfang0"></div>
<div class="profile" id="m_empfang1"></div>
<div class="profile" id="m_mitarbeiter0"></div>
<div class="profile" id="m_mitarbeiter1"></div>
<div class="profile" id="m_mitarbeiter2"></div>
<div class="profile" id="m_mitarbeiter3"></div>
<div class="profile" id="m_mieter0"></div>
<div class="profile" id="m_mieter1"></div>
<div class="profile" id="m_mieter2"></div>
<div class="employeeul">
<ul> <!-- Empfang -->
<li class="employee"></li>
<li class="employee"></li>
</ul>
</div>
<div class="employeeul">
<ul> <!-- Mitarbeiter -->
<li class="employee"></li>
<li class="employee"></li>
<li class="employee"></li>
<li class="employee"></li>
</ul>
</div>
<div class="employeeul">
<ul> <!-- Mieter -->
<li class="employee"></li>
<li class="employee"></li>
<li class="employee"></li>
</ul>
</div>
</div>
It seems like you just need the syntax for displaying/hiding items dynamically when the page has a specific url. In that case, here is a simple JS solution:
//get an array of elements with the class we're interested in working with
var employeeuls = document.getElementsByClassName("employeeul");
//get the current url
var url = window.location.href;
//if the current url is equal to example.php#profile, hide some elements
if(url == "example.php#profile")
{
//iterate over the array and apply the style to hide the elements
for(i=0; i < employeeuls.length; i++)
{
employeeuls[i].style.display = "none";
}
}
//otherwise, the elements should be hidden
else
{
//iterate over the array and apply the style to hide the elements
for(i=0; i < employeeuls.length; i++)
{
employeeuls[i].style.display = "block";
}
}
NOTE: "block" is the default display property for unordered lists.
I understand you're not using jQuery, but I'm going to include the jQuery equivalent for anyone viewing this post in the future:
//variable assigned to all elements with class "employeeul"
var employeeuls = $(".employeeul");
//get the current url
var url = $(location).attr("href");
//apply the style change
if(url == example.php#profile)
{
employeeuls.hide();
}
else employeeuls.show();
If by targeting, you mean the hash value in the URL, you just need to write some JS to grab that hash value and toggle the css. Then toggle show/hide (or a visibility class via jQuery).
$(document).ready(function(){
var $profiles = $('.profile'); // Store all the profiles in a query
var hashTarget = location.hash.replace('#', ''); // Returns hash value
function showTargetedDiv(){
$profiles.hide(); // Hide any divs that may previously be showing
$('#' + hashTarget).show();
}
showTargetedDiv();
$(window).on('hashchange', showTargetedDiv); // Event handler
});

How to show div by dynamic id?

I've got the follow code
<ul>
<li>Google</li>
<li>Facebook</li>
</ul>
<!- hidden divs ->
<div id="1" style="display:none;">Email</div>
<div id="2" style="display:none;"">Social Network</div>
I tried the following code but when I click on a link i would like it to show a div based on the id of the link but it is not working
<script type="text/javascript">
$(document).ready(function()
{
$(".chooserClass").click(function() {
var show = $(this).attr('id');
$(show).show();
});
});
</script>
Change
var show = $(this).attr('id');
$(show).show();
to
var show = $(this).attr('id');
$('#'+ show).show();
You have 2 elements on your page that have th same id, and they are numeric which from experience can cause all kinds of undesired behavior.
The way you want to this is like so:
<ul>
<li>Google</li>
<li>Facebook</li>
</ul>
<!- hidden divs ->
<div id="element1" style="display:none;">Email</div>
<div id="element2" style="display:none;">Social Network</div>
We use a data-show element to store the value of the id of the element that we want to display, in the javascript we can now do this:
<script type="text/javascript">
$(document).ready(function()
{
$(".chooserClass").click(function() {
var show = $(this).data('show');
$('#' + show).show();
});
});
</script>
also note that I am added in the # (for id) in front of the variable when calling the show()
Fiddle demo: http://jsfiddle.net/5U8sW/
Well, here's a quick an dirty answer:
The problem is that you can't have duplicate id's on DOM elements. They should be unique. You can use a data- property to do what you are wanting.
http://jsfiddle.net/725XT/
<ul>
<li>Google</li>
<li>Facebook</li>
</ul>
<!- hidden divs ->
<div id="1" style="display:none;">Email</div>
<div id="2" style="display:none;">Social Network</div>
And your Javascript:
$(document).ready(function()
{
$(".chooserClass").click(function() {
var show = $(this).data('div-id');
console.log(show);
$('#' + show).show();
});
});
When using javascript or jQuery to search for elements with the same IDs, only the first element is picked. I suggest you rename the IDs of the elements to be shown. Take the code below for example.
HTML
<ul>
<li>Google</li>
<li>Facebook</li>
</ul>
<!- hidden divs ->
<div id="d_1" style="display:none;">Email</div>
<div id="d_2" style="display:none;"">Social Network</div>
jQuery
<script type="text/javascript">
$(document).ready(function()
{
$(".chooserClass").click(function() {
var id = $(this).attr('id');
$('#d_'+id).show();
});
});
</script>
jsFiddle
First of all, your IDs should be unique. Thus, the <div> and the <a> must not share the similar ID names. Additionally, AFAIK, in HTML4.1 IDs starting with digits are prohibited(?)
Try the sample I coded above. Since you are using anchors, referencing the 'href' attribute would be more semantically correct.
Cheers!

Weird behavior with .parents() and .closest() when trying to return parent <ul> element id in jQuery

So I've got 2 <ul> containers each with id's. Inside of them are a list of <li> elements.
The first <ul> is <ul id="coaches-list">. The second is <ul id="players-list">.
There are tags within each <li> that have an id called close (which is a link that I'm using as my selector), which will delete each <li> node once clicked. I'm trying to target each <ul> container to see where it is coming from.
My HTML is:
<!-- coaches box -->
<div class="box">
<div class="heading">
<h3 id="coaches-heading">Coaches</h3>
<a id="coaches" class="filter-align-right">clear all</a>
</div>
<ul id="coaches-list" class="list">
<li><span>Hue Jackson<a class="close"></a></span></li>
<li class="red"><span>Steve Mariuchi<a class="close"></a> </span></li>
</ul>
</div>
<!-- players box -->
<div class="box">
<div class="heading">
<h3 id="players-heading">Players</h3>
<a id="players" class="filter-align-right">clear all</a>
</div>
<ul id="players-list" class="list">
<li><span>Steve Young<a class="close"></a></span></li>
<li><span>Gary Plummer<a class="close"></a></span></li>
<li><span>Jerry Rice<a class="close"></a></span></li>
</ul>
</div>
My remove tag function in jQuery is:
function removeSingleTag() {
$(".close").click(function() {
var $currentId = $(".close").closest("ul").attr("id");
alert($currentId);
// find the closest li element and remove it
$(this).closest("li").fadeOut("normal", function() {
$(this).remove();
return;
});
});
}
Whenever I click on each specific tag, it's removing the proper one I clicked on, although when I'm alerting $currentId, if I have:
var $currentId = $(".close").closest("ul").attr("id");
It alerts 'coaches-list' when I'm clicking on a close selector in both <ul id="coaches-list" class="list"></ul> and <ul id="players-list" class="list"></ul>
If I change that to:
var $currentId = $(".close").parents("ul").attr("id");
It has the same behavior as above, but alerts 'players-list', instead.
So when using closest(), it's returning the very first <ul> id, but when using parents(), it's returning the very last <ul> id.
Anyone know what is going on with this whacky behavior?
It's expected behavior.
You should use:
var $currentId = $(this).closest("ul").attr("id");
$(this) points at the clicked .close.
$(".close") points at the first one found.
It's because you run that selector from click handler you should use this instead:
var $currentId = $(this).closest("ul").attr("id");
Try using this function to get the parent:
var $currentId = $(this).parents().first();
I've never used the .closest() function but according to jQuery what you have specified should work. Either way, try that out and tell me how it goes.
You also need to make it so that it selects the current element by using $(this)

Categories