Using javascript for multiple elements [closed] - javascript

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 6 years ago.
Improve this question
I would like to handle several elements that require a specific functionality in our development stage for toggle-like buttons that open and close divs. I say toggle-like because it isn't your standard toggle setup.
The code I have works for a single instance of the buttons and container. Now I need to learn how to apply this to a dozen more which should function independent of each other.
This fiddle shows four examples where the first CSS button is the only one working.
https://jsfiddle.net/e2fexbqp/12/
This is the code that is creating the working example of a single block - two buttons and our div - which should be functional for several other button / div areas.
HTML
<a class="button" id="open">Open</a>
<div id="click-drop" style="display:none">
<h2>Hello World</h2>
<p>You can see me! I'm open! Type your code below.</p>
<textarea></textarea>
<p><a class="button" id="close" style="display:none">Close</a></p>
</div>
Javascript
var open = document.getElementById("open");
var close = document.getElementById("close");
function show(target) {
document.getElementById(target).style.display = 'block';
}
function hide(target) {
document.getElementById(target).style.display = 'none';
}
function hideButton() {
var x = document.getElementById("open");
x.style.display = "none";
var x = document.getElementById("close");
x.style.display = "";
}
function showButton() {
var x = document.getElementById("open");
x.style.display = "";
var x = document.getElementById("close");
x.style.display = "none";
}
open.onclick = function() {show('click-drop');hideButton()}
close.onclick = function() {hide('click-drop');showButton()
I would like something clean and concise as well as unobtrusive.

This demo is pure JavaScript as it is indicated in the tags and implied by the provided code in the question. It has only one eventListener and multiple event.targets BTW, unique ids can only be given to one element. You cannot have multiple ids with the same value. So you'll notice I used only classes no ids.
Advantages
Pure JavaScript and no dependencies on plugins.
Cross-browser with modern browsers.
Having to use only one eventListener is very memory efficient.
It determines exactly which button is clicked without creating an array, or NodeList to iterate through in a loop.
Disadvantages
If you need to be compatible with IE9, then classList has to be replaced with className.
The HTML layout must be in strict pattern. Key elements must be positioned in a predetermined sequence. That's not much of a problem if you have a habit of making organized patterns in markup.
Step by step description is commented in the source.
FIDDLE
SNIPPET
// Reference the parent element
var box = document.querySelector('.box');
// add an eventListener to parent
box.addEventListener('click', toggleBtn, false);
function toggleBtn(event) {
/* This will prevent the <a>nchors from
behaving like normal anchors which
jump from one location to another
*/
event.preventDefault();
// event.target is the element that was clicked (.open/.close .button)
// event.currentTarget is the element that listens for an event (.box)
if (event.target != event.currentTarget) {
var clicked = event.target;
/* If the clicked element has .open class
find the sibling element that was before it and
show it by adding .show class and removing .hide
Then hide clicked element.
*/
if (clicked.classList.contains('open')) {
var drop = clicked.previousElementSibling;
drop.classList.remove('hide');
drop.classList.add('show');
clicked.classList.remove('show');
clicked.classList.add('hide');
} else {
/* Else find clicked parent and hide it
and then show the parent's sibling that is after it.
*/
var drop = clicked.parentElement;
var open = drop.nextElementSibling;
drop.classList.remove('show');
drop.classList.add('hide');
open.classList.remove('hide');
open.classList.add('show');
}
}
/* This prevents the bubbling phase from continuing
up the event chain and triggering any unnecessary
eventListeners
*/
event.stopPropagation();
}
* {
/* Prefix no longer needed */
box-sizing: border-box;
}
.box {
/* Just for demo */
border: 1px dashed red;
}
.button {
text-decoration: none;
font-size: 13px;
line-height: 26px;
height: 28px;
width: 48px;
margin: 0;
padding: 1px;
cursor: pointer;
border-width: 1px;
border-style: solid;
-webkit-appearance: none;
/* Prefix no longer needed for years */
border-radius: 3px;
text-align: center;
}
.click-drop {
border: solid 1px;
border-radius: 3px;
padding: 10px 25px;
}
.hide {
display: none;
}
.show {
display: block;
}
.button.show {
display: inline-block;
}
.close {
display: block;
}
<!--[The order in which elements are positioned is important which will be evident when you review the JavaScript]-->
<!--.box is the 'ancestor/parent' element and event.currentTarget-->
<section class="box">
<h1>Header Content</h1>
<!--Each .click-drop is initially hidden hence it has .hide as a class as well-->
<div class="click-drop hide">
<!--All descendants/children of each .click-drop inherits display:none prop/val from .click-drop.hide-->
<p>Header style</p>
<textarea></textarea>
<a class="close button">Close</a>
</div>
<!--Each .open.button follows it's corresponding .click-drop-->
<a class="open button show">CSS</a>
<div class="click-drop hide">
<p>Header content</p>
<textarea></textarea>
<a class="close button">Close</a>
</div>
<a class="open button show">HTML</a>
<h1>Footer Content</h1>
<div class="click-drop hide">
<p>Footer style</p>
<textarea></textarea>
<a class="close button">Close</a>
</div>
<a class="open button show">CSS</a>
<div class="click-drop hide">
<p>Footer content</p>
<textarea></textarea>
<a class="close button">Close</a>
</div>
<a class="open button show">HTML</a>
</section>

Use event target to style the individual element that got clicked.
anchors = doc.getElementsByClassName("button");
for (var i = 0; i < anchors.length; i++) {
anchors[i].addEventListener("click", function(e){
e.target.classList.toggle('hide');
});
}

Let's explain some points :
IDs in HTML, in a page, shall be unique.
Using classes and jQuery you can achieve this pretty much easily.
I added a span over all the "open button + its corresponding zone" that I set a "zone" class
I put an "open" class to all open links.
I put a "close" class to all close links.
I registered the click for '.zone .open' elements so they hide themselves and show the contained DIV in their parent.
I registered the click for '.zone .close' elements so they hide the DIV under '.zone' element containing them and show the '.open' link under them.
So here is what I've done :
https://jsfiddle.net/e2fexbqp/13/
$(document).ready(function() {
$('.zone .open').click(function() {
$(this).hide();
$(this).parent().find('div').show();
});
$('.zone .close').click(function() {
var parent = $(this).parents('.zone');
parent.children('div').hide();
parent.children('a.open').show();
});
});
.button {
display: inline-block;
text-decoration: none;
font-size: 13px;
line-height: 26px;
height: 28px;
margin: 0;
padding: 0 10px 1px;
cursor: pointer;
border-width: 1px;
border-style: solid;
-webkit-appearance: none;
-webkit-border-radius: 3px;
border-radius: 3px;
white-space: nowrap;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.zone div {
border: solid 1px;
border-radius: 3px;
padding: 10px 25px;
display:none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<h1>Header Content</h1>
<span class="zone">
<a class="button open">CSS</a>
<div>
<p>Header style</p>
<textarea></textarea>
<p><a class="button close">Close</a></p>
</div>
</span>
<span class="zone">
<a class="button open">HTML</a>
<div>
<p>Header content</p>
<textarea></textarea>
<p><a class="button close">Close</a></p>
</div>
</span>
<h1>Footer Content</h1>
<span class="zone">
<a class="button open">CSS</a>
<div>
<p>Footer style</p>
<textarea></textarea>
<p><a class="button close">Close</a></p>
</div>
</span><span class="zone">
<a class="button open">HTML</a>
<div>
<p>Footer content</p>
<textarea></textarea>
<p><a class="button close">Close</a></p>
</div>
</span>

Related

this in the DOM and event listeners

Could some one please tell me how to refactor the JavaScript without "this" in a way that explains the use of "this" in the browser context? (please don't answer the following question with jQuery solutions)
I have passed e (event) into the callback function and implemented:
e.target.classList.toggle("active");
var panel = e.target.nextElementSibling;
What I have implemented has worked. However I want to know to what benefit/why you would use "this" in the context shown, it doesn't seem as declarative as e.target. Is this a function binding issue?
(other snippet related questions below snippet)
I have taken the below snippet from W3schools, it is used for creating an accordion menu:
var acc = document.getElementsByClassName("accordion");
var i;
for (i = 0; i < acc.length; i++) {
acc[i].addEventListener("click", function() {
/* Toggle between adding and removing the "active" class,
to highlight the button that controls the panel */
this.classList.toggle("active");
/* Toggle between hiding and showing the active panel */
var panel = this.nextElementSibling;
if (panel.style.display === "block") {
panel.style.display = "none";
} else {
panel.style.display = "block";
}
});
}
/* Style the buttons that are used to open and close the accordion panel */
.accordion {
background-color: #eee;
color: #444;
cursor: pointer;
padding: 18px;
width: 100%;
text-align: left;
border: none;
outline: none;
transition: 0.4s;
}
/* Add a background color to the button if it is clicked on (add the .active class with JS), and when you move the mouse over it (hover) */
.active, .accordion:hover {
background-color: #ccc;
}
/* Style the accordion panel. Note: hidden by default */
.panel {
padding: 0 18px;
background-color: white;
display: none;
overflow: hidden;
}
<button class="accordion">Section 1</button>
<div class="panel">
<p>Lorem ipsum...</p>
</div>
<button class="accordion">Section 2</button>
<div class="panel">
<p>Lorem ipsum...</p>
</div>
<button class="accordion">Section 3</button>
<div class="panel">
<p>Lorem ipsum...</p>
</div>
Could some one please explain the relationship between the loop and the event listener?
The way I understand it, I would expect that:
every time the DOM is altered/reloads =>
the loop runs =>
adding an event listener on each html collection element=>
if HTML element clicked == true (or) the event is fired
the class is toggled to active
the following if statement is executed and styles may or may not be applied inline to the html element.
This seems like a computationally expensive method of adding event listeners.
Is the above statement that I have written correct if not exactly what is happening?
Is there a more efficient way of writing the event listener loop snippet?
I.e. using event bubbling on a containing element perhaps?
Here's a simple HTML layout:
<main>
<div class='A'></div>
<section></section>
<div class='B'></div>
<section></section>
<div class='C'></div>
</main>
Here's the JavaScript using a programming paradigm called Event Delegation:
document.querySelector('main').addEventListener('click', eventHandler);
Because the majority of the events bubble (click bubbles), the event listener should be registered to an ancestor tag (in this example that would be <main>) of the tags you want to control via events (in this example it's .A, .B, and .C). Now the event handler:
function eventHandler(event) {
const listener = event.currentTarget; // or `this` points to `<main>`
const clicked = event.target; // This is the tag user actually clicked
....
We need to control exactly what reacts to a click and what doesn't react when clicked. We can use if/if else or switch() or even a ternary to delegate events to what we want while excluding what we don't want. Continuing within eventHandler(e)...
....
// All <section>s and even <main> is excluded
if (clicked.matches('div')) {
if (clicked.matches('.A')) {
clicked.style.background = 'red';
}
if (clicked.matches('.C') {
clicked.style.background = 'blue';
}
}
// .B was never mentioned with any specific intructions so it's also excluded.
}
The example below is pretty much the same delegation scheme as the previous explination except with an additional CSS trick with adjacent sibling combinator:
.accordion.active+.panel {
display: block;
}
Whenever a button is .active, the .panel that follows it will disappear.
document.body.addEventListener("click", togglePanel);
function togglePanel(e) {
const clk = e.target;
if (clk.matches('.accordion')) {
clk.classList.toggle("active");
}
};
.accordion {
background-color: #eee;
color: #444;
cursor: pointer;
padding: 18px;
width: 100%;
text-align: left;
border: none;
outline: none;
transition: 0.4s;
}
.active,
.accordion:hover {
background-color: #ccc;
}
.panel {
padding: 0 18px;
background-color: white;
display: none;
overflow: hidden;
}
.accordion.active+.panel {
display: block;
}
<button class="accordion">Section 1</button>
<div class="panel">
<p>Lorem ipsum...</p>
</div>
<button class="accordion">Section 2</button>
<div class="panel">
<p>Lorem ipsum...</p>
</div>
<button class="accordion">Section 3</button>
<div class="panel">
<p>Lorem ipsum...</p>
</div>

How to make an entire div clickable except a deep level child div?

I want to make an entire div clickable except a child div. This child div is not an immediate child of the div, rather it is in a few level deeper. I would like to dynamically exclude this child div by just passing div id or class name.
I tried to solve it with jQuery ".not()" and ".children()" methods, which works. But its static in a sense that I need to know in which level the div is and need to align the methods accordingly. However, I want something dynamic which will take only the div's class name or id, and find it from the DOM tree and exclude it from the new DOM object chain so that the jQuery ".click" and ".hover" function can be applied on the entire div except that particular div.
I have created a dummy example of my problem. In the example, I want to make the entire div (i.e., id = main1) hyperlinked except the "#d3" div.
Here is my JSFiddle: JSFiddle
Example Code:
HTML:
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>
Untitled Document
</title>
</meta>
</head>
<body>
<div class="center border divmain1" id="main1">
<a href="https://www.google.ca" style="display: block">
link
</a>
<p>
Main
</p>
<div class="border-thin divd1" id="d1">
<p>
d1
</p>
</div>
<div class="border-thin divd2" id="d2">
<p>
d2
</p>
<div class="border-thin divd3" id="d3">
<p>
d3
</p>
<div class="border-thin divd4" id="d4">
d4
</div>
<div class="border-thin divd5" id="d5">
d5
</div>
</div>
</div>
</div>
</body>
</html>
CSS:
.border {
border: 5px solid RosyBrown;
}
.border-thin {
border: 2px solid RosyBrown;
}
.divmain1 {
width: 90%;
margin: 0 auto 0 auto;
overflow: hidden;
}
.divd1 {
width: 30%;
float: left;
}
.divd2 {
width: 60%;
float: right;
margin: 0 0 0 3.5%;
}
.divd3 {
margin: auto;
width: 90%;
}
.divd4 {
width: 30%;
}
.divd5 {
width: 30%;
}
jQuery:
// find elements
var main1 = $("#main1")
var d3 = $("#d3")
// handle click and hover pointer
main1.on("click", function(){
window.open('https://www.google.ca');
});
main1.hover(function(){
$(this).css("cursor", "pointer");
});
Could anyone please help me on how to make an entire div clickable and dynamically exclude a child div?
The key thing here is to pass the event object so you can check what is the element actually receiving the click.
Since #d3 contains both #d4 and #d5 I'm assuming you don't want those elements to fire either.
If that's the case, you can use Node.contains() to check if the element is a descendant of your target element.
The Node.contains() method returns a Boolean value indicating whether
a node is a descendant of a given node, i.e. the node itself, one of
its direct children, [...]
If you just want to prevent the action for the element #d3 itself, you don't need to d3.contains and just if (e.target != d3) should do.
// find elements
var main1 = $("#main1")
var d3 = $("#d3").get(0) // Get the HTMLElement
// handle click and hover pointer
main1.on("click", function(e) {
if (!d3.contains(e.target)) {
console.log("I'll open a window");
} else {
console.log("I'm " + e.target.id + " and won't open a window")
}
});
main1.hover(function() {
$(this).css("cursor", "pointer");
});
.border {
border: 5px solid RosyBrown;
}
.border-thin {
border: 2px solid RosyBrown;
}
.divmain1 {
width: 90%;
margin: 0 auto 0 auto;
overflow: hidden;
}
.divd1 {
width: 30%;
float: left;
}
.divd2 {
width: 60%;
float: right;
margin: 0 0 0 3.5%;
}
.divd3 {
margin: auto;
width: 90%;
}
.divd4 {
width: 30%;
}
.divd5 {
width: 30%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="center border divmain1" id="main1">
link
<p>
Main
</p>
<div class="border-thin divd1" id="d1">
<p>d1</p>
</div>
<div class="border-thin divd2" id="d2">
<p>d2</p>
<div class="border-thin divd3" id="d3">
<p>d3</p>
<div class="border-thin divd4" id="d4">d4</div>
<div class="border-thin divd5" id="d5">d5</div>
</div>
</div>
</div>
</body>
</html>
In your jQuery you can run
event.stopPropagation();
within a click event for the div child you don't want to trigger the initial function.
use cancelBubble
for example, to disable your root event on "#d5" div
$('#d5').on('click', function(e){
// stop the event from bubbling.
e.cancelBubble=true
});
I am not much of a fan of jQuery but I can tell you that this can be done with pure JavaScript. All you have to do is to implement an event listener to the top level div and see if the clicked element or it's parent has the targeted class.
Let's take this HTML markup for an example where we will trigger an alert "Target Locked" when someone clicked anything inside divd4 else "General Action"
function HasSelfClassOrParent(element, classname) {
if (element.classList && element.classList.contains(classname))
return true;
return element.parentNode && HasSelfClassOrParent(element.parentNode, classname);
}
let divd2 = document.querySelector(".divd2")
let target = 'divd4'
divd2.addEventListener("click", function(event) {
let isTargetOrChild = HasSelfClassOrParent(event.target, target)
if (isTargetOrChild) {
alert("Target Locked")
} else {
alert("General Action")
}
})
.border {
border: 5px solid RosyBrown;
}
.border-thin {
border: 2px solid RosyBrown;
padding: 20px;
margin-bottom: 10px
}
.divd4{
background: #64B448;
color: #fff;
cursor: pointer;
}
<p>Click on div four and see what happens</p>
<div class="border-thin divd2" id="d2">
<p>I am Div 2</p>
<div class="border-thin divd3" id="d3">
<p>I am Div 3</p>
<div class="border-thin divd4" id="d4">
<p>I am a simple paragraph inside div four</p>
<p>I am a another paragraph inside div four</p>
</div>
<div class="border-thin divd5" id="d5">
I am Div 5
</div>
</div>
</div>

Close all open drop downs and consolidate code if possible

What I need to be able to do is to have the text drop downs close when another is selected so that I do not end up with a bunch of drop downs open on the page at the same time.
I have two text dropdowns that will be used one after the other alternating on a page. In other words accordion1, accordion2, accordion1, accordion2 and so on the reason I have accordion1 and accordion2 is that with my limited experience it is the only way I could figure out change the button color so the list could alternate colors. It would be nice to consolidate the code, but I can live with the extra code if need be.
Here is the code for accordion1
var acc = document.getElementsByClassName("accordion1");
var i;
for (i = 0; i < acc.length; i++) {
acc[i].addEventListener("click", function() {
/* Toggle between adding and removing the "active" class,
to highlight the button that controls the panel */
this.classList.toggle("active1");
/* Toggle between hiding and showing the active panel */
var panel = this.nextElementSibling;
if (panel.style.display === "block") {
panel.style.display = "none";
} else {
panel.style.display = "block";
}
});
}
var acc = document.getElementsByClassName("accordion2");
var i;
for (i = 0; i < acc.length; i++) {
acc[i].addEventListener("click", function() {
/* Toggle between adding and removing the "active" class,
to highlight the button that controls the panel */
this.classList.toggle("active1");
/* Toggle between hiding and showing the active panel */
var panel = this.nextElementSibling;
if (panel.style.display === "block") {
panel.style.display = "none";
} else {
panel.style.display = "block";
}
});
}
.accordion1 {
background-color: #eee;
color: #444;
cursor: pointer;
padding: 18px;
width: 100%;
text-align: left;
border: none;
outline: none;
transition: 0.4s;
}
.accordion2 {
background-color: #8461E8;
color: #444;
cursor: pointer;
padding: 18px;
width: 100%;
text-align: left;
border: none;
outline: none;
transition: 0.4s;
}
/* Add a background color to the button if it is clicked on (add the
.active class with JS), and when you move the mouse over it (hover) */
.active1,
.accordion1:hover {
background-color: #ccc;
}
/* Style the accordion panel. Note: hidden by default */
.panel1 {
padding: 0 18px;
background-color: white;
display: none;
overflow: hidden;
}
.accordion1:after {
content: '\02795';
/* Unicode character for "plus" sign (+) */
font-size: 13px;
color: #777;
float: right;
margin-left: 5px;
}
.accordion2:after {
content: '\02795';
/* Unicode character for "plus" sign (+) */
font-size: 13px;
color: #777;
float: right;
margin-left: 5px;
}
.active1:after {
content: "\2796";
/* Unicode character for "minus" sign (-) */
}
<Section><button class="accordion1"><h3>Alternators and regulators</h3>
</button>
<div id="accordion1-div" class="panel1">
<p>First group of words go here></div>
</Section>
<Section><button class="accordion2"><h3>Batteries and Inverters</h3>
</button>
<div id="accordion-div" class="panel1">
<p>Second set of words go here.</p>
</div>
</Section>
<Section><button class="accordion1"><h3>AC and DC Panels </h3>
</button>
<div id="accordian1-div" class="panel1">
<p>Third set of words reusing "accordion1 go here"</p>
</div>
</Section>
Any help or resources to figure out the needed code would be greatly appreciated.
Question 1 — "How do I not end up with a bunch of drop downs open on the page at the same time":
You close all dropdowns before opening another one. You can also create css rules to display or hide the dropdown. This way, it will be easier to find the currently active dropdown. See code below.
Question 2 — "How can I make the list alternate colors"
You can add more than one class to an element. Simply create color classes and add them to the right elements. See code below.
Notes:
Use the CSS selectors instead of JavaScript to show/hide the panel
Element h3 is not allowed as child of element button. Do it the other way round.
Use the same JavaScript code and CSS for all accordions.
Edit (scrollIntoView)
I added code to automatically scroll the window so that the active tab is visible.
It works only on Chrome, Firefox and Opera. Use this polyfill iamdustan/smoothscroll to use it in other browsers. See compatibility here and all functions here.
// Query all accordions
var accordions = document.querySelectorAll('.accordion');
for (var i = 0; i < accordions.length; i++) {
accordions[i].addEventListener('click', function() {
// Get the currently active accordion
var active = document.querySelector('.accordion.active');
// If there is one, deactivate it
if (active) {
active.classList.remove('active');
}
// Activate the new accordion, if it's not the one you just deactivated
if (active !== this) {
this.classList.add('active');
// Use scrollIntoView to adjust the window scroll position to show the content.
this.scrollIntoView({
behavior: 'smooth'
});
}
});
}
.accordion .header button {
text-align: left;
padding: 18px;
background: transparent;
border: none;
outline: none;
cursor: pointer;
width: 100%;
color: #444;
width: 100%;
transition: 0.4s;
}
/* Set the color according to the modifier class */
.accordion.gray button {
background-color: #eee;
}
.accordion.purple button {
background-color: #8461E8;
}
.accordion.active button,
.accordion button:hover {
background-color: #ccc;
}
.accordion .panel {
padding: 0 18px;
background-color: white;
display: none;
overflow: hidden;
}
/* Show the panel if the accordion is active */
.accordion.active .panel {
display: block;
}
.accordion button:after {
content: '\02795';
font-size: 13px;
color: #777;
float: right;
margin-left: 5px;
}
.accordion.active button:after {
content: "\2796";
}
<section>
<!-- Each accordion is wrapped by a div with the class 'accordion' -->
<!-- 'accordion' is the component, 'gray' is the color modifier -->
<div class="accordion gray">
<!-- h3 can contain a button -->
<h3 class="header">
<button>Alternators and regulators</button>
</h3>
<div class="panel">
<p>
First group of words go here.<br/> I'm afraid I just blue myself. No… but I'd like to be asked! Michael! It's called 'taking advantage.' It's what gets you ahead in life. Now, when you do this without getting punched in the chest, you'll have
more fun.
</p>
</div>
</div>
</section>
<section>
<!-- Use the 'purple' modifier class here -->
<div class="accordion purple">
<h3 class="header">
<button>Batteries and Inverters</button>
</h3>
<div class="panel">
<p>
Second set of words go here.<br/> Steve Holt! I don't criticize you! And if you're worried about criticism, sometimes a diet is the best defense. That's why you always leave a note! Well, what do you expect, mother? I don't criticize you! And
if you're worried about criticism, sometimes a diet is the best defense.<br/>
<br/> Across from where? As you may or may not know, Lindsay and I have hit a bit of a rough patch. Now, when you do this without getting punched in the chest, you'll have more fun. No… but I'd like to be asked!
</p>
</div>
</div>
</section>
<section>
<div class="accordion gray">
<h3 class="header">
<button>AC and DC Panels
</button>
</h3>
<div class="panel">
<p>
Third set of words go here.<br/> That's why you always leave a note! Not tricks, Michael, illusions. As you may or may not know, Lindsay and I have hit a bit of a rough patch. It's called 'taking advantage.' It's what gets you ahead in life.<br/>
<br/> Say goodbye to these, because it's the last time! First place chick is hot, but has an attitude, doesn't date magicians. I'm afraid I just blue myself. I'm afraid I just blue myself. I'm afraid I just blue myself.
</p>
</div>
</div>
</section>

How to run Jscript without postback

I'm trying to build an "accordion" style collapsible div into my web page as described here on w3c schools...
accordion description
I've got most of it working - my code is this:
ASP:
<div class="col-md-4">
<button class="accordion">Section 1</button>
<div class="content">
<asp:Table ID="Consumable_table" runat="server">
<asp:TableHeaderRow>
<asp:TableHeaderCell>
<h2>
<u>Consumable Stock</u>
</h2>
</asp:TableHeaderCell>
</asp:TableHeaderRow>
</asp:Table>
</div>
</div>
CSS:
.accordion {
background-color: #eee;
color: #444;
cursor: pointer;
padding: 18px;
width: 100%;
border: none;
text-align: left;
outline: none;
font-size: 15px;
transition: 0.4s;}
.active, .accordion:hover {
background-color: #ccc;}
.content {
padding: 0 18px;
background-color: white;
max-height: 0;
overflow: hidden;
transition: max-height 0.2s ease-out;}
And I've added the following Jscript:
$(document).ready(function () {
var acc = document.getElementsByClassName("accordion");
var i;
for (i = 0; i < acc.length; i++) {
acc[i].addEventListener("click", function () {
this.classList.toggle("active");
var panel = this.nextElementSibling;
if (panel.style.maxHeight) {
panel.style.maxHeight = null;
} else {
panel.style.maxHeight = panel.scrollHeight + "px";
}
return false;
});
}
});
The code seems to work fine and when I click the Accordion element it expands - But it then seems to post back and the accordion collapses again and doesn't display.
My question is how can I have it expand and stay expanded as described in the tutorial. I've seen a number of answers here and on various sites that suggests "return false" might be enough.
Does this have anything to do with the ASP table inside the div?
The dafault behaviour of the HTML button is to submit the form when clicked (its type is submit by default). All you need to do is to add type="button" attribute to the element, like this:
<button class="accordion" type="button">Section 1</button>
That should resolve the problem - it indicates that the button is just a simple clickable button, without any special action.
This answer also covers it: <button> vs. <input type="button" />. Which to use?
There are two ways,
By default the button behavior like submit button so postback will happen. If you want to prevent postback you can use below code.
<button class="accordion" onclick="return false;">Section 1</button>
You can use type attribute to prevent submit behavior.
<button type="button" class="accordion">Section 1</button>

how to prevent focus on any button, input, etc on a div?

I have a div which is a container of various things. Sometimes it contains some simply tables, and other layout stuff. But sometimes it contains buttons and forms.
This container div can show another div modally. Which I achieved by simply making its position: absolute, and have its top/bottom/left/right 0.
It looks nice but when I press the tab button focus can go to the elements on the div behind. How can I prevent this?
I know I can disable focus on one element by setting tabIndex=-1 so I could iterate however when the modal disappears I would need to restore all this elements. Which means extra work. I wonder if there is a general way of doing this with jQuery or maybe jqueryui or vanilla js?
EDIT:
Working example in jsbin:
https://jsbin.com/veciju/1/edit?html,css,js,output
I am not sure what is the exact issue without the fiddle, and did not check the code. But here is my solution (pure javascript) hope it helps
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<div id="container">
<p id="filler">
Hello World.
</p>
<form id="myForm">
<input type="text" />
<input type="submit" value="submit"/>
</form><br>
<button id="openModal" onclick="openModal();"> Open Modal</button>
<div id="modal" class="hidden">
<p id="modelP"> This is a modal DIV. You cannot escape me</p>
<button id="closeModal" onclick="closeModal();">Close Me</button>
</div>
</div>
</body>
<style>
#container{
margin: 50px auto;
padding: 100px;
color: white;
width: 50%;
height:400px;
background-color: black;
text-align: center;
}
.hidden{
display: none;
}
#modal{
background-color: green;
border: 5px solid red;
z-index: 100;
width:80%;
height: 80%;
left: auto;
}
</style>
<script>
function openModal(){
var modalElement = document.getElementById('modal');
var others = document.querySelectorAll('* :not(#closeModal) ');
modalElement.removeAttribute('class');
for (i=0; i<others.length;i++){
console.log(others[i]);
others[i].setAttribute('disabled','disabled');
}
}
function closeModal(){
var modalElement = document.getElementById('modal');
var others = document.querySelectorAll('* :not(#closeModal) ');
modalElement.className='hidden';
for (i=0; i<others.length;i++){
console.log(others[i]);
others[i].removeAttribute('disabled');
}
}
</script>

Categories

Resources