Display none some content and block one element - javascript

I would like to make 3 buttons with each one make all the content div to display: none and depending on the button you have click one of the content div change to display: block. For example, If I click on the second button It will show only the second div content.
function showPanel(id) {
var elements = document.getElementsByClassName("content");
for (let i = 0; i < elements.length; i++) {
document.getElementById(i).style.display = "none";
}
document.getElementById(id).style.display = "block";
}
<button onclick="showPanel('1')">test1</button>
<button onclick="showPanel('2')">test2</button>
<button onclick="showPanel('3')">test3</button>
<div class="content">
<div id="1" class="content">
<p>TEST1</p>
</div>
<div id="2" class="content">
<p class="other">TEST2</p>
</div>
<div id="3" class="content ">
<p class="other">TEST3</p>
</div>
</div>

There's a couple of issues in your code. Firstly length is a property, not a method, so you don't need the () suffix to invoke it. Secondly, there's no className attribute in HTML. This should just be class. Lastly the parent container shares the same class as the elements you're hiding, so all the child elements get hidden, even if they have display: block applied to them.
With these issues corrected, your code would look like this:
function showPanel(id) {
var elements = document.getElementsByClassName("panel");
for (let i = 0; i < elements.length; i++) {
elements[i].style.display = "none";
}
document.getElementById(id).style.display = "block";
}
<button onclick="showPanel('p1')">test1</button>
<button onclick="showPanel('p2')">test2</button>
<button onclick="showPanel('p3')">test3</button>
<div class="content">
<div id="p1" class="panel">
<p>TEST1</p>
</div>
<div id="p2" class="panel">
<p class="other">TEST2</p>
</div>
<div id="p3" class="panel">
<p class="other">TEST3</p>
</div>
</div>
However it's worth noting that using onX attributes is outdated and not good practice. A better solution would be to use unobtrusive event handlers and provide custom metadata to the event handler through data attributes placed on the elements.
The improved version of the logic would look like this:
let buttons = document.querySelectorAll('button');
let panels = document.querySelectorAll('.panel');
buttons.forEach(button => {
button.addEventListener('click', e => {
panels.forEach(panel => {
panel.style.display = panel.id === e.target.dataset.panel ? 'block' : 'none';
});
});
});
<button data-panel="1">test1</button>
<button data-panel="2">test2</button>
<button data-panel="3">test3</button>
<div class="content">
<div id="1" class="panel">
<p>TEST1</p>
</div>
<div id="2" class="panel">
<p class="other">TEST2</p>
</div>
<div id="3" class="panel">
<p class="other">TEST3</p>
</div>
</div>

No need for JS or Jquery. Instead of a button you can use an anchor tag. Then you calling with the anchor the id of the element. Last but not least you make the boxes hidden through CSS and use the :target selector to display the elements:
.content {
display: none;
}
.content:target {
display: block;
}
test1<br>
test2<br>
test3<br>
<div class="content-container">
<div id="1" class="content">
<p>TEST1</p>
</div>
<div id="2" class="content">
<p class="other">TEST2</p>
</div>
<div id="3" class="content ">
<p class="other">TEST3</p>
</div>
</div>

Multiple issues.
Length can be calculated using elements.length and not elements.length()
You have given same class name to both the parent and the child divs. So hiding all elements with class name content will hide your whole parents itself. So after updating style.display = "block" to the required target, it will not work. Because your parent is already style.display = "none". So you should make a logic update there. So I changed the parent class name.
function showPanel(id) {
var elements = document.getElementsByClassName("content");
for (let i = 0; i < elements.length; i++) {
elements[i].style.display = "none";
}
document.getElementById(id).style.display = "block";
}
<button onclick="showPanel('1')">test1</button>
<button onclick="showPanel('2')">test2</button>
<button onclick="showPanel('3')">test3</button>
<div>
<div id="1" class="content">
<p>TEST1</p>
</div>
<div id="2" class="content">
<p class="other">TEST2</p>
</div>
<div id="3" class="content ">
<p class="other">TEST3</p>
</div>
</div>

A more elegant way I might approach a prob,problem like this would be to tie the panels and their triggers together using data-attributes. This way, you don't risk conflicts with other IDs that m ay be the same on the page (IDs should always be unique).
Before setting up my event listener, I would initialize an openPanel variable and set it to any panel that is already created with the active class name. Whenever we open a new panel, we will overwrite this variable vaklue, so we don't need to do a new querySelctor each time.
Then, in the CSS, rather than hiding all panels and then showing the one with the active class, we can write a single style that hides any panels without the active class using the :not negation selector.
This is how that would look (initializing this with panel #1 open by default, but you can simply remove the active class from it in the HTML if you don't want that):
let openPanel = document.querySelector('[data-panel-id].active');
document.addEventListener('click', e => {
if (e.target?.matches?.('[data-panel-target]')) {
const id = e.target.dataset.panelTarget;
if (id) {
const panel = document.querySelector(`[data-panel-id="${id}"]`);
if (panel) {
openPanel?.classList.remove('active');
panel.classList.add('active');
openPanel = panel;
}
}
}
})
[data-panel-id]:not(.active) {
display: none;
}
<button data-panel-target="1">test1</button>
<button data-panel-target="2">test2</button>
<button data-panel-target="3">test3</button>
<main>
<div data-panel-id="1" class="active">
<p>TEST #1</p>
</div>
<div data-panel-id="2">
<p>TEST #2</p>
</div>
<div data-panel-id="3">
<p>TEST #3</p>
</div>
</main>

I already submitted a separate solution with my preferred recommendation, but I wanted to provide an answer to your question using the same approach you started with so as not to deviate from the code you already have in place.
The code you already had in place was actually fairly close to working already. The main issue I saw was that you were using document.getElementById(i) where you should actually have been using elements[i]. We can improve this further though, by replacing the for loop with a for..of loop, and determining inline whether the current element being evaluated is the one we want to show. If so, we use 'block', otherwise 'none'.
After initializing our function, we can call it on one of our IDs within the JS to have one panel open by default. **It's also important that the parent of all these .content elements NOT contain the class name content as well, as that would conflict with your function. I have replaced that parent element with a simple <main>…</main> element.
Here is how I would achieve solving this using your existing approach:
function showPanel(contentId) {
const elements = Array.from(document.getElementsByClassName('content'));
for (const element of elements) {
element.style.display = element.id === contentId ? 'block' : 'none';
}
}
showPanel('1');
<button onclick="showPanel('1')">test1</button>
<button onclick="showPanel('2')">test2</button>
<button onclick="showPanel('3')">test3</button>
<main>
<div id="1" class="content">
<p>TEST1</p>
</div>
<div id="2" class="content">
<p>TEST2</p>
</div>
<div id="3" class="content ">
<p>TEST3</p>
</div>
</main>

Related

Is there anyway to simplify this Javascript code

I have this code that, when a certain card is clicked, its content is displayed on an overlay card. But the way I have it right now is to repetitive:
HTML:
<div class="card c1">
<img src="max.png" width="65px">
<div class="text">
<h3 class="firstName">Owen</h3>
<h3 class="lastName">Osagiede</h3>
<p>[email]</p>
<p>[city]</p>
</div>
</div>
<div class="card c2">
<img src="max.png" width="60px">
<div class="text">
<h3 class="firstName">Kanye</h3>
<h3 class="lastName">West</h3>
<p>[email]</p>
<p>[city]</p>
</div>
</div>
<div class="card c3">
<img src="max.png" width="65px">
<div class="text">
<h3 class="firstName">Quando</h3>
<h3 class="lastName">Rondo</h3>
<p>[email]</p>
<p>[city]</p>
</div>
</div>
JS:
function overlayUser(){
card[1].addEventListener('click', function(){
first.innerHTML = card[1].getElementsByTagName('h3')[0].innerHTML;
last.innerHTML = card[1].getElementsByTagName('h3')[1].innerHTML;
});
card[2].addEventListener('click', function(){
first.innerHTML = card[2].getElementsByTagName('h3')[0].innerHTML;
last.innerHTML = card[2].getElementsByTagName('h3')[1].innerHTML;
});
card[3].addEventListener('click', function(){
first.innerHTML = card[3].getElementsByTagName('h3')[0].innerHTML;
last.innerHTML = card[3].getElementsByTagName('h3')[1].innerHTML;
});
I have tried to loop over it with a for loop, but keep getting an error:
`function overlayUser(){
for (i = 0; i < card.length; i++){
card[i].addEventListener('click', function(){
first.innerHTML = card[i].getElementsByTagName('h3')[0].innerHTML;
last.innerHTML = card[i].getElementsByTagName('h3')[1].innerHTML;
});
}
}`
In a DOM event handler, the current element is this. Therefore you can write a single function for all of them:
function handleClick () {
first.innerHTML = this.getElementsByTagName('h3')[0].innerHTML;
last.innerHTML = this.getElementsByTagName('h3')[1].innerHTML;
}
function overlayUser(){
for (i = 0; i < card.length; i++){
card[i].addEventListener('click', handleClick);
}
}
The this API is the original API for finding out which element caused the event. Thus it is very compatible with all browsers.
Alternatively, if you feel uncomfortable mixing the usage of this you can also find out the current element from the event object:
function handleClick (event) {
let card = event.target;
first.innerHTML = card.getElementsByTagName('h3')[0].innerHTML;
last.innerHTML = card.getElementsByTagName('h3')[1].innerHTML;
}
The event object is a slightly less ancient API but is compatible with everything from IE8 and above.
Additionaly you can use event bubbling/capturing to even get rid of the for loop. Just install the event on the parent element of all three cards and let event.target sort out which card caused the event:
parentDiv.addEventListener('click', handleClick);
Instead of looping over all the individual elements that you want to have event handlers and hooking each up, set a single handler on an ancestor element and allow the event to bubble up to that element. Then, when handling it, look at the event.target, which refers to the actual element that triggered the event. This is called event delegation.
Also, do not use .getElementsByTagName() in 2020. That is a 25+ year old API that returns a live node list that can dramatically hurt performance, especially since you are only interested in a single element when you use it.
Addtionally, never use .innerHTML if you can avoid it. It has security and performance implications. Since you aren't actually working with a string that needs any HTML parsed, you should use .textContent.
Finally, you should not be using h3 unless it is to create a sub-section of a pre-existing h2. Headings are meant to divide your document into ordered sections and these sections are used by those who rely on assistive technologies to navigate a document. If you are just using the h3 because of the styling the browser applies to the text, you should instead just use a p and then use CSS to style it the way you want.
// Get references to first and last (for this demo)
let first = document.querySelector(".first");
let last = document.querySelector(".last");
// Just handle the click event at the wrapper of all the cards
document.querySelector(".wrapper").addEventListener("click", function (event){
// Then access the content of the card that actaully triggered the event
first.textContent = event.target.closest(".card").querySelector("h3").textContent;
last.textContent = event.target.closest(".card").querySelector("h3:nth-child(2)").textContent;
});
/* Just for demo */
.results {
position:sticky;
left:50%;
top:0;
background-color:#e0e0e0;
border:2px solid red;
}
<div class="results">
<div class="first"></div>
<div class="last"></div>
</div>
<div class="wrapper">
<div class="card c1">
<img src="max.png" width="65px">
<div class="text">
<h3 class="firstName">Owen</h3>
<h3 class="lastName">Osagiede</h3>
<p>[email]</p>
<p>[city]</p>
</div>
</div>
<div class="card c2">
<img src="max.png" width="60px">
<div class="text">
<h3 class="firstName">Kanye</h3>
<h3 class="lastName">West</h3>
<p>[email]</p>
<p>[city]</p>
</div>
</div>
<div class="card c3">
<img src="max.png" width="65px">
<div class="text">
<h3 class="firstName">Quando</h3>
<h3 class="lastName">Rondo</h3>
<p>[email]</p>
<p>[city]</p>
</div>
</div>
</div>

javascript toggle showing and hiding several div elements

I have two divs on a page (id's MAY and JUNE) and two buttons on the page. The page startes off by showing the May div, with the June div hidden using css display: none
I am trying to create the correct javascript that will toggle between the two of them, but (after searching on here) I can only manage to get one to work.
Codepen showing issue is https://codepen.io/billteale/pen/zwBBez
<a href="#" id="button" >MAY</a>
<a href="#" id="button" >JUNE</a>
<!-- first div, shows on page load -->
<div id="MAY">
<div style="background-color: lightgrey"><h1 style="padding: 5px"><strong>May 2017</strong></h1>
</div>
<!-- second div, hidden originally -->
<div class="hidden" id="JUNE">
<div style="background-color: lightgrey"><h1 style="padding: 5px"><strong>June 2017</strong></h1>
</div>
...and the current js is
var button = document.getElementById('button'); // Assumes element with id='button'
button.onclick = function() {
var div = document.getElementById('MAY');
if (div.style.display !== 'none') {
div.style.display = 'none';
}
else {
div.style.display = 'block';
}
};
Eventually I will have four or more divs to toggle between, with each button showing its relevant div, and hiding the others.
Can anybody tell me how to add to the code I have here to make this work for multiple elements?
It can be done by setting the div id's in the anchor tag's href attribute, and showing the corresponding div while hiding the rest. It can be done for any number of div's with no extra script, Just add the new div id to the new anchor tags href. You should give a common class to all the div's like month to select them all.
$("a.btn").click(function() {
var id = $(this).attr("href");
$("div.month:visible").hide();
$(id).show();
});
.hidden {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
MAY
JUNE
<!-- first div, shows on page load -->
<div id="MAY" class="month">
<div style="background-color: lightgrey">
<h1 style="padding: 5px"><strong>May 2017</strong></h1>
</div>
</div>
<!-- second div, hidden originally -->
<div class="month hidden" id="JUNE">
<div style="background-color: lightgrey">
<h1 style="padding: 5px"><strong>June 2017</strong></h1>
</div>
</div>
First you add a "div-toggle" class to each one of the divs you want to toggle. After that, you bind click events on your buttons, firing a function which takes an identifier as argument.
The function will run through your divs and set the one that has the argument id as visible, and hide the others.
This way you can add more divs to be toggled. You just have to mark them with the "div-toggle" class, set their id's and create their respective buttons.
var divs = document.getElementsByClassName('div-toggle');
function toggle(id) {
for (var i = 0; i < divs.length; i++) {
var div = divs[i];
if (div.id == id)
div.style.display = 'block';
else
div.style.display = 'none';
}
}
<a href="#" onclick="toggle('MAY')" >MAY</a>
<a href="#" onclick="toggle('JUNE')" >JUNE</a>
<!-- first div, shows on page load -->
<div class="div-toggle" style="display:block;" id="MAY">
<div style="background-color: lightgrey">
<h1 style="padding: 5px"><strong>May 2017</strong></h1>
</div>
</div>
<!-- second div, hidden originally -->
<div class="div-toggle" style="display:none;" id="JUNE">
<div style="background-color: lightgrey">
<h1 style="padding: 5px"><strong>June 2017</strong></h1>
</div>
</div>
div.style.visibility = "hidden"
this will completely hide your div. I'm pretty sure this is what you are asking for
also instead of that you can make a separate function and add o'clock to div
<div onclick="nameoffunction()"></div>
the function can take in a parameter and each div on click function can have the parameter of its id
Your div were messed up! The snippet is working now with the help of jQuery.
$("#JUNE").hide();
$("#MAY").show();
$('#button-may').on("click", function() {
$("#JUNE").hide();
$("#MAY").show();
});
$('#button-june').on("click", function() {
$("#JUNE").show();
$("#MAY").hide();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
MAY
JUNE
<!-- first div, shows on page load -->
<div id="MAY">
<div style="background-color: lightgrey">
<h1 style="padding: 5px"><strong>May 2017</strong></h1>
</div>
</div>
<!-- second div, hidden originally -->
<div class="hidden" id="JUNE">
<div style="background-color: lightgrey">
<h1 style="padding: 5px"><strong>June 2017</strong></h1>
</div>
</div>

How to get the ID of a clicked element, when it or its children are clicked?

UPDATED
I think I may have inadvertently made the question confusing. This is an update that is more specific with updated code based on comments and answer I have been given so far. Thank you to everyone that has taken the time to comment and answer.
How can I get the ID of a <div> with the class of .button when I have a click listener for .button. If .button or any of its children are clicked, it should return the ID for that particular div with the class of .button.
This is what I have so far: New JSFiddle
HTML
<div class="row">
<div id="b1" class="button">
<h2>Button 1</h2>
</div>
<div id="b2" class="button">
<h2>Button 2</h2>
</div>
<div id="b3" class="button">
<h2>Button 3</h2>
</div>
</div>
jQuery
var selected = "";
$('.button').on('click', function(e) {
selected = e.target.id;
$('.button').css('backgroundColor', '#becde5');
$('#' + selected).css('backgroundColor', '#3b71c6');
$('#selected').html(selected);
});
This is almost correct but does not propagate, if I click on a <h2> the function does not work. However if I click on the .button div itself it works.
Initial Question
I am trying to create a general function that can identify what child was selected from its parents click listener. The child may have its own children that would all be considered part of the same element so that if any of these children where selected they should also elicit the same response from the click listener.
This is an example of what I have working so far: JSFiddle
HTML consisting of three buttons that all have one child <h2> tag and share the <div class="row"> as their parent.
<div class="row">
<div class="b1 button">
<h2 class="b1">Button 1</h2>
</div>
<div class="b2 button">
<h2 class="b2">Button 2</h2>
</div>
<div class="b3 button">
<h2 class="b3">Button 3</h2>
</div>
</div>
jQuery that listens for a click on <div class="row">. It retrieves the first class name of the clicked element and stores it in a variable. The elicited response in this case is a change of the CSS style background-color though this is arbitrary and would change depending on the use of the function.
var selected = "";
$('.row').on('click', function(e) {
selected = e.target.className.split(" ")[0];
$('.b1, .b2, .b3').css('backgroundColor', '#becde5');
$("." + selected).css('backgroundColor', '#3b71c6');
$('#selected').html(selected);
});
The fact that I am adding a lot of classes to elements purely to identify them on a click seems like it would not scale very well and is generally a bad approach. This method also means that I would always have to put the class name that identifies what element was selected at the beginning of its HTML class attribute. This could potentially clash with other functions using the same method.
Is there a better way to identify what child element was selected from its parents click listener, where a child may have other children that also require the same response from the listener?
EDIT based on the edited question:
I think that what you really want is the id of the element that triggered the event.
But by using e.target you have the target element... which is not necessarily the element that triggered the event.
See in this updated Fiddle.
So simply use $(this) as the selector to retrieve the id... Using .attr("id").
;)
Answer to the initial question:
To determine what can be "selected", I used a "clickable" class.
To avoid using id or class as an identifier to determine what has been clicked,
a data attribute can be usefull.
I used data-id... But you can use whatever you want, like: data-selected or data-target, and assign whatever value to it.
In the below code, I made two exactly identical rows, except their data-id value.
var selected = "";
$('.clickable').on('click', function(e) {
e.stopPropagation(); // To prevent bubbling.
// Reset all bg colors
$('.button').css('backgroundColor', 'initial');
$('.row').css('backgroundColor', 'initial');
// Find exactly what was clicked
if ($(this).hasClass("row")) {
var row = $(this).data("id");
selected = row + " (whole)";
}
if ($(this).hasClass("button")) {
// Find in which row
var row = $(this).closest(".row").data("id");
var btn = $(this).data("id");
selected = btn + " in " + row;
}
// Pale all buttons
$('.button').css('backgroundColor', '#becde5');
// Change bg color of the selected element
$(this).css('backgroundColor', '#3b71c6');
$('#selected').html(selected);
});
.row {
display: table;
width: 100%;
color: white;
border-spacing: 20px;
}
.button {
display: table-cell;
border-radius: 12px;
background-color: #6fa1f2;
text-align: center;
}
#selected {
font-size: 30px;
color: green;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<span>Selected : <span id="selected">no selection</span></span><br>
<div class="row clickable" data-id="row1">
<div class="button clickable" data-id="btn1">
<h2>Button 1</h2>
</div>
<div class="button clickable" data-id="btn2">
<h2>Button 2</h2>
</div>
<div class="button clickable" data-id="btn3">
<h2>Button 3</h2>
</div>
</div>
<br>
<div class="row clickable" data-id="row2">
<div class="button clickable" data-id="btn1">
<h2>Button 1</h2>
</div>
<div class="button clickable" data-id="btn2">
<h2>Button 2</h2>
</div>
<div class="button clickable" data-id="btn3">
<h2>Button 3</h2>
</div>
</div>
no need to id the subject, since it was the one clicked, i.e. e.target which with jQuery you cant select like $(e.target) without any trouble
then you need .closest('.button') to search up to the parent .button (if any)
$('.row').on('click', function(e) {
$('.row > .button').css('backgroundColor', '#becde5');
$(e.target).closest('.button').css('backgroundColor', '#3b71c6');
console.log($(e.target).html());
});
.button {
cursor: pointer;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<div class="row">
<div class="button">
<h2>Button 1</h2>
</div>
<div class="button">
<h2>Button 2</h2>
</div>
<div class="button">
<h2>Button 3</h2>
</div>
</div>
If you avoid giving an identifier (classes, IDs, etc) you'd need to do some manual checking for tag type to see what you clicked on (so basically, an identifier as well)
Here's an example, and not very memory efficient method
jsfiddle example
$('.row, .row *').on('click', function(e) {
e.stopPropagation()
$('.button').removeClass('active')
$('.button').css('backgroundColor', '#becde5');
$(this).toggleClass('active')
$('#selected').html(e.target.tagName + ': ' + e.target.className);
});
If you bind a click to div.row and clicked the h2 tag inside the button, and want to manipulate the h2 tag, you could check its tagName- but that less scalable than your OP.

Performance wise and fastest way to get all element with Id inside a container element

I am trying to refactor and make a performance wise code.
The idea of the code is to update the id or value of all element with id or value that needs to be updated that happens when an element has been removed / deleted
So what I am trying to do is get all element with Id or value inside a container element (which is possible to be nested in 2 to 4).
At the moment, I am using jQuery to this task. I added a class on every element that has Id and use jQuery .find() to get all of this element using the class I've assign to them .. which is I really hate about my code and wanted to change as well if there's another best way to do it.
So is there a fastest way and performance wise at the same time to do this task?
$("button").on("click", function(){
$($(this).val()).remove();
updateParagraph();
});
function updateParagraph() {
$(".paragraphs").each(function(index, data){
var dataId = data.id.split("-");
var idIndex = dataId[dataId.length-1];
var index = index + 1;
if (index != idIndex) {
dataId.splice(-1, 1);
dataId.push(index);
dataId = dataId.join("-");
$(this).attr("id", dataId);
setChildElementsId($(this), index)
}
});
}
function setChildElementsId(parent, inx) {
$(parent).find(".id-holder").each(function(index, data){
if (data.id) {
var dataId = data.id.split("-");
dataId.splice(-1, 1);
dataId.push(inx);
dataId = dataId.join("-");
$(this).attr("id", dataId);
if(isParagraph(data.tagName)) {
$(this).text(inx);
}
}
else if (data.value) {
var dataValue = data.value.split("-");
dataValue.splice(-1, 1);
dataValue.push(inx);
dataValue = dataValue.join("-");
$(this).val(dataValue);
}
});
}
function isParagraph(tagName){
return tagName == "P";
};
<div id="container-1" class="paragraphs">
<div id="header-container-id-1" class="id-holder">
<h4>Header</h4>
</div>
<div id="paragraph-container-id-1" class="id-holder">
<p id="id-1" class="id-holder">1</p>
</div>
<button value="#container-1" class="id-holder">delete</button>
</div>
<div id="container-2" class="paragraphs">
<div id="header-container-id-2" class="id-holder">
<h4>Header</h4>
</div>
<div id="paragraph-container-id-2" class="id-holder">
<p id="id-2" class="id-holder">2</p>
</div>
<button value="#container-2" class="id-holder">delete</button>
</div>
<div id="container-3" class="paragraphs">
<div id="header-container-id-3" class="id-holder">
<h4>Header</h4>
</div>
<div id="paragraph-container-id-3" class="id-holder">
<p id="id-3" class="id-holder">3</p>
</div>
<button value="#container-3" class="id-holder">delete</button>
</div>
<div id="container-4" class="paragraphs">
<div id="header-container-id-4" class="id-holder">
<h4>Header</h4>
</div>
<div id="paragraph-container-id-4" class="id-holder">
<p id="id-4" class="id-holder">4</p>
</div>
<button value="#container-4" class="id-holder">delete</button>
</div>
<div id="container-5" class="paragraphs">
<div id="header-container-id-5" class="id-holder">
<h4>Header</h4>
</div>
<div id="paragraph-container-id-5" class="id-holder">
<p id="id-5" class="id-holder">5</p>
</div>
<button value="#container-5" class="id-holder">delete</button>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
If I understand your question correctly, you're looking to more elegantly identify which elements have an id of the form "__-id-#" or simply "id-#".
If this is the case, take a look at some more advanced jQuery selectors. One in particular which might meet your needs is the Attribute Contains Selector.
For instance, I think $(parent).find("[id*='id-']") might do what you're looking to do.
While I understand what you're attempting to do, I don't quite understand why you're doing this in the first place.
Unless there are restrictions that force you to structure your HTML like you did, well, don't. Aim for the simplest structure:
<div id="container-123" class="paragraphs">
<h4>Header</h4>
<p>1</p>
<button type="button">delete</button>
</div>
Remove the <div>s around the <h4> and the <p> unless you need them for some styling reason. The <button> doesn't need to know its ID, because it's a child element of the container, so you're delete handler could make use of that fact:
$(document.body).on("click", "button", function() {
$(this).closest('.paragraphs').remove();
});
If there are outside forces that require a specific ID (e.g. for linking to an anchor), keep that on the top container element. If your CSS targets elements by ID, refactor the CSS.
I would like to answer your question using javascript. In fact you don't need any of those id-s
I hope I'm not too late.
let buttons = Array.from(document.querySelectorAll(".id-holder"));
buttons.forEach(b => {
//for each button add an event listener
b.addEventListener("click", () => {
b.parentElement.parentElement.removeChild(b.parentElement);
resetNums();
});
});
function resetNums(){
// reseting the text inside the p
let btns = Array.from(document.querySelectorAll(".id-holder"));
btns.forEach((bt,i)=>{
let theP = bt.parentElement.querySelector("p");
theP.innerHTML = i+1;
})
}
<div>
<div>
<h4>Header1</h4>
</div>
<div>
<p>1</p>
</div>
<button class="id-holder">delete</button>
</div>
<div>
<div>
<h4>Header2</h4>
</div>
<div>
<p>2</p>
</div>
<button class="id-holder">delete</button>
</div>
<div>
<div>
<h4>Header3</h4>
</div>
<div>
<p>3</p>
</div>
<button class="id-holder">delete</button>
</div>
<div>
<div>
<h4>Header4</h4>
</div>
<div>
<p>4</p>
</div>
<button class="id-holder">delete</button>
</div>
<div>
<div>
<h4>Header5</h4>
</div>
<div>
<p>5</p>
</div>
<button class="id-holder">delete</button>
</div>

Apply style by javascript without using Id

My html page content is below
<div>
<div>
Summary 1
</div>
<div style="display:none">
Details 1
</div>
<button>Read More</button>
</div>
Details content is collapsed initially. When user clicks the Read More button, I need to show details content. I can make it possible. i will define id for details div tag and javascript for onclick event of button. Using id i will change the div style display.
But i have multiple list of sections based on the back end data. so my page would be renderd like below
<div>
<div>
Summary 1
</div>
<div style="display:none">
Details 1
</div>
<button>Read More</button>
</div>
<div>
<div>
Summary 2
</div>
<div style="display:none">
Details 2
</div>
<button>Read More</button>
</div>
<div>
<div>
Summary 3
</div>
<div style="display:none">
Details 3
</div>
<button>Read More</button>
</div>
Now How can i acheive the expand and collapse functionality when Read More button is clicked.
Using plain javascript and with the strategic addition of some classes, you could do this which would make each button into a toggle that even changes it's text according to the toggle state. Then one piece of javascript would serve for all the repeated instances of this structure and the code would be independent of the exact HTML layout of the summary, details and button (as long as they retained the same classes and were in the same container div.
HTML:
<div>
<div>
Summary 1
</div>
<div class="details" style="display:none">
Details 1
</div>
<button class="readMore">Read More</button>
</div>
<div>
<div>
Summary 2
</div>
<div class="details" style="display:none">
Details 2
</div>
<button class="readMore">Read More</button>
</div>
<div>
<div>
Summary 3
</div>
<div class="details" style="display:none">
Details 3
</div>
<button class="readMore">Read More</button>
</div>​
And the javascript:
function toggleVis(el) {
var vis = el.style.display != "none";
if (vis) {
el.style.display = "none";
} else {
el.style.display = "block";
}
return(!vis);
}
(function() {
var readMore = document.getElementsByClassName("readMore");
for (var i = 0; i < readMore.length; i++) {
readMore[i].onclick = function(e) {
var vis = toggleVis(e.target.parentNode.getElementsByClassName("details")[0]);
e.target.innerHTML = vis ? "Read Less" : "Read More";
}
}
})();
Working Demo: http://jsfiddle.net/jfriend00/aMBkJ/
Note: This would require a shim for getElementsByClassName() on older versions of IE.
​
By using jQuery .prev() you may achieve it easily.
$('button').on('click', function(e){
$(this).prev('div').toggle();
});
DEMO
You can try this with jquery
<button class="readmore">Read More</button>
jQuery
$('.readmore').click(function(){
$(this).prev().show();
});
Here it is how you do it using jquery:
The HTML code:
<div class="stuff">
<dl id="faq">
<dt>What shouldn't I do to the bird?</dt>
<dd>Never try to treat a fracture at home.</dd>
</div>
The JQuery code:
jQuery(document).ready(function() {
$('#faq').find('dd').hide().end().find('dt').click(function(){
$(this).next().slideToggle();
});
});

Categories