Toggle <span> text which contains inner HTML element - javascript

On the button click, I want to toggle its text from 'View More' to 'View Less'. However, the span element contains another element inside of it (Font Awesome icon). When I toggle text of a span element, the element inside of it disappears. You can see it in the snippet below.
I also tried this solution:
$('.button span').text(($('.button span').text()=='View More<i class="fas fa-angle-down"></i>') ? 'View Less<i class="fas fa-angle-up"></i>' : 'View More<i class="fas fa-angle-down"></i>');
But it inserts the i element as a span text, instead as an element.
NOTE: I can't keep the i element outside of the span element because I have certain animations in CSS.
$('.button').click(function() {
$('.button i').toggleClass('fa-angle-up fa-angle-down');
$('.button span').text(($('.button span').text()=='View More') ? 'View Less' : 'View More');
});
.button {
width: 250px;
padding: 12px 0;
text-transform: uppercase;
cursor: pointer;
}
.button i {
margin-left: 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="https://kit.fontawesome.com/a671c6b423.js" crossorigin="anonymous"></script>
<button type="button" name="button" value="" class="button">
<span>View More<i class="fas fa-angle-down"></i></span>
</button>

$('.button').click(function() {
$('.button span').html(($('.button span').text()=='View More') ? 'View Less<i class="fas fa-angle-up">' : 'View More<i class="fas fa-angle-down">');
});
.button {
width: 250px;
padding: 12px 0;
text-transform: uppercase;
cursor: pointer;
}
.button i {
margin-left: 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="https://kit.fontawesome.com/a671c6b423.js" crossorigin="anonymous"></script>
<button type="button" name="button" value="" class="button">
<span>View More<i class="fas fa-angle-down"></i></span>
</button>

This can be fixed using the html() function of JQuery. That will have the same functionality as the text() function, but adds the option to set html elements.
This link provides you with the JQuery documentation.

what about to wrap the text which you want to change into an own span with an id? then you could change the text without touching the fontawesome icon

I would simply add a data attribute to the texts and toggle only that portion instead of trying to complicate things, like this:
$('.button').click(function() {
$('.button i').toggleClass('fa-angle-up fa-angle-down');
const currentText = $('[data-view-more]').text();
const updatedText = currentText === 'View More' ? 'View Less' : 'View More';
$('[data-view-more]').text(updatedText);
});
.button {
width: 250px;
padding: 12px 0;
text-transform: uppercase;
cursor: pointer;
}
.button i {
margin-left: 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="https://kit.fontawesome.com/a671c6b423.js" crossorigin="anonymous"></script>
<button type="button" name="button" value="" class="button">
<span>
<span data-view-more>View More</span>
<i class="fas fa-angle-down"></i>
</span>
</button>
As you can see I now target data-view-more text when toggling the text and then I target the icon to toggle that.

Just for fun and for the idea: no jquery, use event delegation and a data-attribute to toggle text and icon
document.addEventListener("click", handle);
function handle(evt) {
const bttn = evt.target.closest("[data-view]");
return bttn
? toggleBttn(bttn, bttn.dataset.view === "more")
: true;
}
function toggleBttn(bttn, isClosed) {
let classes = ["fa-angle-down", "fa-angle-up"];
classes = isClosed ? classes : classes.reverse();
bttn.querySelector("i").classList.replace(...classes);
bttn.dataset.view = isClosed ? "less" : "more";
}
.button {
width: 250px;
padding: 12px 0;
text-transform: uppercase;
cursor: pointer;
}
[data-view]:before {
content: 'view 'attr(data-view);
margin-right: 10px;
}
<script src="https://kit.fontawesome.com/a671c6b423.js" crossorigin="anonymous"></script>
<button type="button" data-view="more" class="button">
<i class="fas fa-angle-down"></i>
</button>

When you keep the icon out of the span, it works like you expect it:
<button type="button" name="button" value="" class="button">
<span>View More></span>
<i class="fas fa-angle-down"></i
</button>

Related

How to Update getElementsByClassName after doing something?

if (document.querySelector(".delete-filter") !== null) {
let dltbtn = document.getElementsByClassName("delete-filter");
let contbtn = document.getElementsByClassName("filter-solid");
for (let i = 0; i < dltbtn.length; i++) {
dltbtn[i].onclick = function() {
contbtn[i].remove();
}
}
}
.filter-solid {
display: inline-block;
border: 1px solid #faa938;
border-radius: 2vw;
font-size: 13px;
padding: 5px 8px;
color: #525666;
margin: 4px 0;
}
.filter-solid button {
border: none;
background: none;
color: #525666;
}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" integrity="sha512-SfTiTlX6kk+qitfevl/7LibUOeJWlt9rbyDn92a1DqWOw9vWG2MFoays0sgObmWazO5BQPiFucnnEAjpAB+/Sw==" crossorigin="anonymous" referrerpolicy="no-referrer">
<div>
<span class="filter-solid"><span> فقط کالاهای تخفیف دار </span> <button class="delete-filter"><i class="fa fa-times"></i></button></span>
<span class="filter-solid"><span> از <span>200,000</span> تا <span>1,200,000</span> تومان </span> <button class="delete-filter"><i class="fa fa-times"></i></button></span>
<span class="filter-solid"><span> رنگ آبی </span> <button class="delete-filter"><i class="fa fa-times"></i></button></span>
</div>
In above code I want to remove an element after click, but the problem is when I delete elements (from left) the count of dltbtn and contbtn is not updating. I mean when I have 4 elements there is [0, 1, 2, 3] array, so when I delete first element the array should be [0, 1, 2] in order, but it will not be updated. how should I fix this?
If you use .addEventListener() instead of .onclick, and DOM traversal to find the container of the clicked button, you don't need dltbtn, contbtn or an index.
this in the event handler assigned with .addEventListener() is the clicked element -> the button.
With .closest(".filter-solid") we travel the DOM up to the first element that matches the selector ".filter-solid" (in this case .parentNode) would do the same -> the container that should be removed.
document.querySelectorAll(".delete-filter")
.forEach(function(btn) {
btn.addEventListener("click", function() {
const container = this.closest(".filter-solid");
if (container) {
container.remove();
}
});
})
.filter-solid {
display: inline-block;
border: 1px solid #faa938;
padding: 5px 8px;
margin: 4px 0;
}
<div>
<span class="filter-solid"><span> فقط کالاهای تخفیف دار </span> <button class="delete-filter"><i class="fa fa-times">X</i></button></span>
<span class="filter-solid"><span> از <span>200,000</span> تا <span>1,200,000</span> تومان </span> <button class="delete-filter"><i class="fa fa-times">X</i></button></span>
<span class="filter-solid"><span> رنگ آبی </span> <button class="delete-filter"><i class="fa fa-times">X</i></button></span>
</div>
The main issue is that getElementsByClassName() returns a live collection. To quote the MDN page:
Warning: This is a live HTMLCollection. Changes in the DOM will reflect in the array as the changes occur. If an element selected by this array no longer qualifies for the selector, it will automatically be removed. Be aware of this for iteration purposes.
Meaning that contbtn[i].remove() will implicitly remove the current element from the array (because it is removed from the DOM), shifting all elements that come after it.
An easy change would be swapping from getElementsByClassName() to querySelectorAll() which does not not return a live collection.
let dltbtn = document.querySelectorAll(".delete-filter");
let contbtn = document.querySelectorAll(".filter-solid");
With this change elements in the resulting collection won't shift when contbtn[i].remove() is called.
Another good solution in this scenario would be to use event delegation. This means adding an event listener to the wrapping <div> which checks if the .delete-filter is clicked and removes the associated .filter-solid.
This also simplifies adding new elements, since you no longer need to add event listeners on those new elements.
const containers = document.querySelectorAll(".filter-solid-container");
for (const container of containers) {
container.addEventListener("click", function ({ target }) {
// only search within the container by addeding the container selector
const dlt = target.closest(".filter-solid-container, .delete-filter");
// return if not clicked on .delete-filter
// (`dlt` will be set to the container)
if (dlt == container) return;
// I assume that .filter-solid is always present around a .delete-filter
// find and remove it
dlt.closest(".filter-solid").remove();
});
}
// demo: adding a new filter without fumbling with event handlers
const addFilter = document.querySelector("#add-filter");
addFilter.addEventListener("click", function () {
containers[0].innerHTML += `
<span class="filter-solid">
<span>test</span>
<button class="delete-filter"><i class="fa fa-times"></i></button>
</span>
`;
});
.filter-solid {
display: inline-block;
border: 1px solid #faa938;
border-radius: 2vw;
font-size: 13px;
padding: 5px 8px;
color: #525666;
margin: 4px 0;
}
.filter-solid button {
border: none;
background: none;
color: #525666;
}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" integrity="sha512-SfTiTlX6kk+qitfevl/7LibUOeJWlt9rbyDn92a1DqWOw9vWG2MFoays0sgObmWazO5BQPiFucnnEAjpAB+/Sw==" crossorigin="anonymous" referrerpolicy="no-referrer">
<div class="filter-solid-container">
<span class="filter-solid"><span> فقط کالاهای تخفیف دار </span> <button class="delete-filter"><i class="fa fa-times"></i></button></span>
<span class="filter-solid"><span> از <span>200,000</span> تا <span>1,200,000</span> تومان </span> <button class="delete-filter"><i class="fa fa-times"></i></button></span>
<span class="filter-solid"><span> رنگ آبی </span> <button class="delete-filter"><i class="fa fa-times"></i></button></span>
</div>
<button id="add-filter" type="button">add filter</button>

Change styles to toggled divs

Im using filtered divs and I want to change the flex-direction of each section only when that specific section is toggled, then go back to original styles when going back to "Show all"
Here is the link for the filtered divs
https://www.w3schools.com/howto/tryit.asp?filename=tryhow_js_filter_elements
The W3 Schools code is not very good. It can be improved greatly but the use of data attributes, proper event listeners and event bubbling
All we need to to to get your "flex switch" happening is add/remove a class to the ".container" to indicate if filtered or not
var container = document.querySelector(".container");
//Add an event listener to the div containing the buttons
document.getElementById("myBtnContainer").addEventListener("click", function(event) {
//remove active class from previous active button
this.querySelector(".active").classList.remove("active");
//add active class to clicked item
event.target.classList.add("active");
//Add filitered to ".container" if "All" clicked, remove otherwise
container.classList.toggle("filtered", event.target.dataset.target !== "all")
//Display chosen elements
var elements = container.querySelectorAll(".filterDiv");
for (var i = 0; i < elements.length; i++) {
//Long version of below
//var categoryArray = elements[i].dataset.category.split(",");
//var hasTargetCategory = categoryArray.includes(event.target.dataset.target);
//elements[i].classList.toggle("show",hasTargetCategory);
elements[i].classList.toggle("show", elements[i].dataset.category.split(",").includes(event.target.dataset.target));
}
})
.filterDiv {
background-color: #2196F3;
color: #ffffff;
width: 100px;
line-height: 100px;
text-align: center;
margin: 2px;
flex: none;
}
.container {
margin-top: 20px;
display: flex;
flex-wrap: wrap;
}
/* Style the buttons */
.btn {
border: none;
outline: none;
padding: 12px 16px;
background-color: #f1f1f1;
cursor: pointer;
}
.btn:hover {
background-color: #ddd;
}
.btn.active {
background-color: #666;
color: white;
}
/*Class to change flex direction*/
.filtered {
flex-direction: column;
}
/*Hide elements without the show class*/
.filtered>.filterDiv:not(.show) {
display: none;
}
<div id="myBtnContainer">
<button class="btn active" data-target="all"> Show all</button>
<button class="btn" data-target="cars"> Cars</button>
<button class="btn" data-target="animals"> Animals</button>
<button class="btn" data-target="fruits"> Fruits</button>
<button class="btn" data-target="colors"> Colors</button>
</div>
<div class="container">
<div class="filterDiv" data-category="cars">BMW</div>
<div class="filterDiv" data-category="colors,fruits">Orange</div>
<div class="filterDiv" data-category="cars">Volvo</div>
<div class="filterDiv" data-category="colors">Red</div>
<div class="filterDiv" data-category="cars,animals">Mustang</div>
<div class="filterDiv" data-category="colors">Blue</div>
<div class="filterDiv" data-category="animals">Cat</div>
<div class="filterDiv" data-category="animals">Dog</div>
<div class="filterDiv" data-category="fruits">Melon</div>
<div class="filterDiv" data-category="fruits,animals">Kiwi</div>
<div class="filterDiv" data-category="fruits">Banana</div>
<div class="filterDiv" data-category="fruits">Lemon</div>
<div class="filterDiv" data-category="animals">Cow</div>
</div>
I didn't understand what you meant by "flexible steering", would it be to replace the phrase "Show all" with the active section? This can be done with jquery, but you would have to replace the element that houses the text.
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button type="button" id="all">Show all</button>
<button type="button" id="cars">cars</button>
<script>
$("#cars").on("click", function(){
$("#all").text('Cars');
});
$("#all").on("click", function(){
$("#all").text('Show All');
});
</script>
Alternative without jquery
<button id="all">Show All</button>
<button id="cars" onclick="cars()">Cars</button>
<script>
function cars() {
document.getElementById("all").innerHTML = "Cars";
}
</script>
Alternative to build the tab without so much javascript and css
Bootstrap Collapse: You can use Bootstrap Colapse which already has a structure ready and you would only have to organize the HTML with the divs as per the documentation: https://getbootstrap.com/docs/4.0/components/collapse/
Javascript behavior: Like the previous one, this is a tabbed browsing API, which is identical to the code you are using, with the difference that here you would be using the Bootstrap structure and will not require many modifications, you should note the similarity between this and the previous one, in fact what changes is only the usability, the situations in which you will use one or the other, but the purpose is the same, both seek to hide elements.
https://getbootstrap.com/docs/4.0/components/navs/#javascript-behavior

How to display a Save icon button on an inline text editing placeholder

How to add a save button something like this
<a class="btn btn-xs btn-default" href="#" ><i class="fa fa-check"></i></a>
on an inline text edit filed.
I want to add above textbox just to the right side of the input filed so that onclick of it, it will save the texts to the span.
Also is it possible the icon will visible on-mouse hover to .editableTextbox?
$(function() {
$(".editableTextbox").each(function() {
var t = $(this);
t.after("<input type = 'text' style = 'display:none' />");
var i = $(this).next();
i[0].name = this.id.replace("lbl", "txt"), i.val(t.html()), t.click(function() {
$(this).hide(), $(this).next().show()
}), i.focusout(function() {
$(this).hide(), $(this).prev().html($(this).val()), $(this).prev().show()
})
})
});
.editableTextbox{padding: 2px; border:1px solid #CCC;}
.hiddencontrol{
display: none;
}
.showcontrol:hover .hiddencontrol{
display : block;
}
.editableTextbox:hover {cursor: pointer; background-color: #D9EDF8; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<span class="editableTextbox"> Rename me </span>
You can use .append() method to insert the specified content as the last child of each element.
$(function() {
$(".editableTextbox").each(function() {
var t = $(this);
t.after("<input type = 'text' style = 'display:none' />");
var i = $(this).next();
i[0].name = this.id.replace("lbl", "txt"), i.val(t.html()), t.click(function() {
$(this).hide(), $(this).next().show()
}), i.focusout(function() {
$(this).hide(), $(this).prev().html($(this).val()), $(this).prev().show()
$(".editableTextbox").append("<a class='btn btn-xs btn-default' href='#'><i class='fa fa-check'></i></a>");
})
})
});
.editableTextbox {
padding: 2px;
border: 1px solid #CCC;
}
.hiddencontrol {
display: none;
}
.showcontrol:hover .hiddencontrol {
display: block;
}
.editableTextbox:hover {
cursor: pointer;
background-color: #D9EDF8;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"></script>
<span class="editableTextbox"> Rename me </span>

JS code to show / hide all parent / child divs on a page

I have a simple bit of JS used to show / hide DIVs:
function HideShow(e, itm_id) {
var tbl = document.getElementById(itm_id);
if (tbl.style.display == ""){
e.innerHTML = "<i class='fa fa-plus' aria-hidden='true'></i>";
tbl.style.display = "none"; }
else {
e.innerHTML = "<i class='fa fa-minus' aria-hidden='true'></i>";
tbl.style.display = ""; }
}
This is a working example of the code on Codepen: Show Hide Divs without jQuery
This is an example of one section:
<div id="activities" style="margin-bottom:50px;">
<div style="color: #000; background: #eee; border-bottom:1px solid #ccc; padding:5px;">
<h1 class="heading"><i class='fa fa-minus' aria-hidden='true'></i> Activities <span style="color:#ccc;"></span></h1>
</div>
<div id="parent_activities" style="background: #fff; padding:20px;">
<div id="activities__award-medal" style="background: #fff; padding-left:10px; background:#f1f1f1; border-top:1px solid #fff; font-size:30px;"><i class='fa fa-minus' aria-hidden='true'></i> award-medal <span style="color:#ccc;"></span></div>
<div id="child_award-medal" style="background: #fff; padding:20px;">
<ul class="gallery grid">
<li>
<a href="#">
<img title="military medal - 🎖️" src="https://cdn.jsdelivr.net/emojione/assets/svg/1f396.svg" style="width:64x; height:64px" role="presentation">
</a>
</li>
</ul>
</div>
<div id="activities__event" style="background: #fff; padding-left:10px; background:#f1f1f1; border-top:1px solid #fff; font-size:30px;"><i class='fa fa-minus' aria-hidden='true'></i> event <span style="color:#ccc;"></span></div>
<div id="child_event" style="background: #fff; padding:20px;">
<ul class="gallery grid">
<li>
<a href="#">
<img title="jack-o-lantern - 🎃" src="https://cdn.jsdelivr.net/emojione/assets/svg/1f383.svg" style="width:64x; height:64px" role="presentation">
</a>
</li>
</ul>
</div>
</div>
</div>
The top level example has an id of parent_activities and then there are two child values:
child_award-medal
child_event
I'd like to work out how to add two links:
A link to toggle the HideShow function for the parents so that all divs with an ID starting with parent_ are shown / hidden
A link to toggle the HideShow function for the children so that all divs with an ID starting with child_ are shown / hidden
I'm not sure how I'd go about that though.
Any advice much appreciated. Thanks
Note: this isn't a fully complete solution. The intention is to assist you in the parts that are giving you pause.
Try not to embed JavaScript in your HTML body; it's unnecessary markup and makes it difficult to track down and debug errors. I did not change your existing calls, but demonstrate how it can be done by using addEventListener with the newer code
You can target your elements using document.querySelectorAll and looking for the prefix you're interested in (e.g., parent_, child_). Which prefixes to use have been added to the links in the data-selector attributes
because the toggling action is not going to another page, these should be buttons or spans
to hide elements, you can use the Bootstrap display classes, as I have used d-none which stands for display none. The Bootstrap library provides these to make it especially easier for responsive layouts
many of your inline-CSS should be in classes, this is to both reduce your markup and make it more organized
// So forEach can be used on 'querySelectorAll' and 'getElementsByClassName' collections
HTMLCollection.prototype.forEach = NodeList.prototype.forEach = Array.prototype.forEach;
function HideShow(e, itm_id) {
var tbl = document.getElementById(itm_id);
if (tbl.style.display == "") {
e.innerHTML = "<i class='fa fa-plus' aria-hidden='true'></i>";
tbl.style.display = "none";
} else {
e.innerHTML = "<i class='fa fa-minus' aria-hidden='true'></i>";
tbl.style.display = "";
}
}
// -----------------------------------------------------------
// NEW Code
// New toggle links
let toggles = document.getElementsByClassName('toggler');
// Attach click event
toggles.forEach(link => link.addEventListener('click', fnToggleElement))
// Event handler definition
function fnToggleElement() {
let elements = document.querySelectorAll(`[id^="${this.dataset.selector}"]`)
let className = 'd-none'
elements.forEach(el => {
let fas = el.parentElement.closest('.item,.sub-container,.menu-container').querySelectorAll('.fa')
if (el.classList.contains(className)) {
el.classList.remove(className)
fas.forEach(fa => {
fa.classList.remove('fa-plus')
fa.classList.add('fa-minus')
})
} else {
el.classList.add(className)
fas.forEach(fa => {
fa.classList.remove('fa-minus')
fa.classList.add('fa-plus')
})
}
})
}
.menu-container {
margin-bottom: 50px;
}
.sub-container {
padding: 20px;
}
.heading {
color: #000;
background: #eee;
border-bottom: 1px solid #ccc;
padding: 5px;
}
.indent {
background: #fff;
padding: 20px;
}
.icon {
width: 64px;
height: 64px;
}
.item {
background: #fff;
padding-left: 10px;
background: #f1f1f1;
border-top: 1px solid #fff;
font-size: 30px;
}
.toggler {
cursor: pointer;
display: inline-block;
}
.gallery {
width: 100%;
*width: 99.94877049180327%;
margin: 0;
padding: 0;
}
.gallery.grid li {
margin: 2px 5px;
}
.gallery.grid li {
margin: 2px 5px;
display: block;
}
.gallery.grid li:hover {
background: #ccc;
}
.gallery.grid li {
display: inline-block;
border-top: 1px solid #eee;
border-right: 1px solid #ccc;
border-bottom: 1px solid #ccc;
border-left: 1px solid #eee;
padding: 6px;
position: relative;
-moz-box-sizing: border-box;
border-radius: 3px 3px 3px 3px;
background: #fff;
}
.gallery a {
display: block;
}
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css" rel="stylesheet" />
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet" />
<div class="container-fluid">
<div class="row">
<div class="col-sm"><span class="toggler btn-link" data-selector="parent_">Toggle Parents</span></div>
<div class="col-sm"><span class="toggler btn-link" data-selector="child_">Toggle Children</span></div>
</div>
</div>
<div class="container-fluid">
<div id="activities" class="menu-container">
<h1 class="heading">
<a href="javascript:;" onclick="HideShow(this,'parent_activities')">
<i class='fa fa-minus' aria-hidden='true'></i>
</a> Activities
<span style="color:#ccc;"></span>
</h1>
<div id="parent_activities" class="sub-container">
<div id="activities__award-medal" class="item">
<a href="javascript:;" onclick="HideShow(this,'child_award-medal')">
<i class='fa fa-minus' aria-hidden='true'></i>
</a> award-medal
<span style="color:#ccc;"></span>
</div>
<div id="child_award-medal" class="indent">
<ul class="gallery grid">
<li>
<a href="# ">
<img title="military medal - 🎖️" src="https://cdn.jsdelivr.net/emojione/assets/svg/1f396.svg " class="icon" role="presentation">
</a>
</li>
</ul>
</div>
<div id="activities__event " class="item">
<a href="javascript:; " onclick="HideShow(this, 'child_event') ">
<i class='fa fa-minus' aria-hidden='true'></i>
</a> event
<span style="color:#ccc; "></span>
</div>
<div id="child_event " class="indent">
<ul class="gallery grid ">
<li>
<a href="# ">
<img title="jack-o-lantern - 🎃" src="https://cdn.jsdelivr.net/emojione/assets/svg/1f383.svg" class="icon" role="presentation">
</a>
</li>
</ul>
</div>
</div>
</div>
<div id="animals-nature" class="menu-container">
<h1 class="heading"><i class='fa fa-minus' aria-hidden='true'></i> Animals & Nature <span style="color:#ccc;"></span></h1>
<div id="parent_animals-nature" class="sub-container">
<div id="animals-nature__animal-amphibian " class="item ">
<a href="javascript:;" onclick="HideShow(this, 'child_animal-amphibian')">
<i class='fa fa-minus' aria-hidden='true'></i>
</a> animal-amphibian
<span style="color:#ccc;"></span>
</div>
<div id="child_animal-amphibian" class="indent">
<ul class="gallery grid">
<li>
<a href="# ">
<img title="frog face - 🐸 " src="https://cdn.jsdelivr.net/emojione/assets/svg/1f438.svg " style="width:64x; height:64px " role="presentation ">
</a>
</li>
</ul>
</div>
<div id="animals-nature__animal-bird " class="item">
<a href="javascript:;" onclick="HideShow(this, 'child_animal-bird')">
<i class='fa fa-minus' aria-hidden='true'></i>
</a> animal-bird
<span style="color:#ccc;"></span>
</div>
<div id="child_animal-bird" class="indent">
<ul class="gallery grid">
<li>
<a href="# ">
<img title="turkey - 🦃 " src="https://cdn.jsdelivr.net/emojione/assets/svg/1f983.svg " style="width:64x; height:64px " role="presentation ">
</a>
</li>
</ul>
</div>
</div>
</div>
Try the following selector and apply:
document.querySelectorAll('[id^="child_"]')
See the below snippet for an example:
function toggleIdStartingWith( prefix = 'parent_' ){
// Select all IDs starting with prefix and turn this NodeList into an array
// so we can loop through it easily later.
var all = [...document.querySelectorAll(`[id^="${prefix}"]`)];
// Determine whether we want to turn them on or off by
// checking the first element. You might want to also check
// if any elements are found at all before doing this.
var hidden = all[ 0 ].style.display === 'none';
// Apply the display style to all.
all.forEach(element => {
element.style.display = hidden ? '' : 'none';
});
// Return the inverted hidden value, which is what we applied.
// Useful if you want to toggle stuff, and then see what the result
// was in the code that called the function.
return !hidden;
}
// For testing purposes I am hooking two buttons up for testing this.
document.getElementById('hideshow_parents').addEventListener( 'click', event => {
event.preventDefault()
event.target.textContent = toggleIdStartingWith( 'parent_' )
? 'Show all Parents'
: 'Hide all Parents'
})
document.getElementById('hideshow_children').addEventListener( 'click', event => {
event.preventDefault()
event.target.textContent = toggleIdStartingWith( 'child_' )
? 'Show all Children'
: 'Hide all Children'
})
<div id="parent_1">Parent</div>
<div id="child_1">Child</div>
<div id="parent_2">Parent</div>
<div id="child_2">Child</div>
<div id="parent_3">Parent</div>
<div id="child_3">Child</div>
<div id="parent_4">Parent</div>
<div id="child_4">Child</div>
<div id="parent_5">Parent</div>
<div id="child_5">Child</div>
<button id="hideshow_parents">Hide/Show Parents</button>
<button id="hideshow_children">Hide/Show Children</button>
As you asked in the comment, switching the classes depending on the toggle state is easy too. I personally think you shouldn't mix html and interactivity, so I am going to use addEventListener in my example:
function toggleIdStartingWith( prefix = 'parent_' ){
var all = [...document.querySelectorAll(`[id^="${prefix}"]`)];
var hidden = all[ 0 ].style.display === 'none';
all.forEach(element => {
element.style.display = hidden ? '' : 'none';
});
return !hidden;
}
document.querySelector('h1').addEventListener( 'click', event => {
event.preventDefault()
if( toggleIdStartingWith( 'parent_' ) ){
event.target.textContent = 'Show';
event.target.classList.remove( 'fa-minus' )
event.target.classList.add( 'fa-plus' )
} else {
event.target.textContent = 'Hide';
event.target.classList.add( 'fa-minus' )
event.target.classList.remove( 'fa-plus' )
}
})
.fa-minus:before { content: '-'; }
.fa-plus:before { content: '+'; }
<div id="parent_1">Parent</div>
<div id="parent_2">Parent</div>
<div id="parent_3">Parent</div>
<div id="parent_4">Parent</div>
<div id="parent_5">Parent</div>
<h1 class="fa-minus">Hide</h1>
If you are insistent on getting it as an onclick in your html, just wrap it in a function:
function toggle( target, prefix ){
if( toggleIdStartingWith( prefix ) ){
target.textContent = 'Show';
target.classList.remove( 'fa-minus' )
target.classList.add( 'fa-plus' )
} else {
target.textContent = 'Hide';
target.classList.add( 'fa-minus' )
target.classList.remove( 'fa-plus' )
}
}
And call it as such:
<h1 onclick="toggle( this, 'parent_); return false;'"></h1>
Also, just so you know, it might be good to return false if you are going to use onclick handlers in HTML to prevent the default events from occuring. Then you can just leave your link set to # instead of the ugly javascript:;.
You should use querySelectorAll() to select "IDs starting with...". This can be done like document.querySelectorAll('[id^="start_"]') and then you iterate through the elements applying the style to hide or show.
Check out this fiddle: https://jsfiddle.net/1c38dezk/
You should use querySelectorAll() to select "IDs starting with...".
Have a nice day

click function does not working with ng-if

If i use like following,I got what i need.. Here is the code.
<style>
.moreMenu {
position: absolute;
right: 0px;
z-index: 10;
padding: 10px;
color: #666;
border-radius: 0 0 0 4px;
background: #FFF;
display: none;
border-top: 1px solid #DDD;
}
</style>
<i class="fa fa-ellipsis-v tbButton otherOptions rightSide" aria-hidden="true"></i>
<div class="moreMenu">
heloo
</div>
<script>
$(".otherOptions").click(function () {
$(".moreMenu").slideToggle("fast");
});
</script>
But if i use ng-if condition,
<i class="fa fa-ellipsis-v tbButton otherOptions rightSide" aria-hidden="true" ng-if="member==''"></i>
click function is not working.
I solved the issue..
<i class="fa fa-ellipsis-v tbButton otherOptions rightSide" aria-hidden="true" ng-if=members==''" ng-click="mymore()"></i>
// controller
$scope.mymore = function(){
$(".moreMenu").slideToggle("fast");
}
Thanks all for the informations...
It would be better to use ng-click but if you need to use jQuery's click event, you can add a filtered click event to the body:
$('body').on('click', '.otherOptions', function() {
$('.moreMenu').slideToggle('fast');
});
this will add an event handler on the body but will only trigger if the event bubbles up from the otherOptions element. This is an approach to handling dynamic content with jQuery events
#athi is your answer is a proper answer. But as per the question I have answered here use ng-show instead of ng-if.
angular.module("a",[]).controller("ac",function($scope){
});
.otherOptions
{
color: #666;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="a" ng-controller="ac">
<input class="otherOptions" type="button" value="hello" ng-click="mymore()" ng-show=true>
<div class="moreMenu">
heloodfg
</div>
</div>
<script>
$(".otherOptions").click(function () {
$(".moreMenu").slideToggle("fast");
});
</script>

Categories