Javascript show/hide div requires two clicks - javascript

I've got code to show/hide two divs based upon the clicking of an arrow. However, the second div requires two clicks before it hides and the arrow doesn't change as expected. The top div works perfectly. Any suggestions about what I'm doing wrong, please?
EDIT - Thanks to the two posters who have pointed out my naming error in the arrows. However, after loading the page, the second div still requires two clicks before it toggles.
HTML
<div id="start_conditions_arrow" class="arrow_down" onclick="toggleDiv('start_conditions')"></div>
<h2>Starting Conditions</h2>
<div id="start_conditions">
<%= render :partial => 'start_conditions', :object => #page.start_conditions %>
</div>
<div id="probability_arrow" class="arrow_right" onclick="toggleDiv('probability_inputs')"></div>
<h2>Probability Inputs</h2>
<div id="probability_inputs">
<%= render :partial => 'probability_inputs', :object => #page.probability_inputs %>
</div>
Javascript
var toggleDiv = function(id){
var tag = document.getElementById(id).style;
if(tag.display == 'none'){
document.getElementById(id).style.display='block';
document.getElementById(id + '_arrow').className='arrow_down';
} else {
document.getElementById(id).style.display='none';
document.getElementById(id + '_arrow').className='arrow_right';
}
};
CSS
.arrow_down, .arrow_right {
width: 0;
height: 0;
margin: 12px 12px 0 0;
float: left;
cursor: pointer;
}
.arrow_down {
border-left: 10px solid transparent;
border-right: 10px solid transparent;
border-top: 18px solid #d5d5d5;
}
.arrow_right {
border-top: 10px solid transparent;
border-bottom: 10px solid transparent;
border-left: 18px solid #d5d5d5;
}
#probability_inputs {
display: none;
}
#start_conditions {
display: none;
}
Here's a Codepen including the above: https://codepen.io/anon/pen/yXozYJ

The second arrow element should have probability_inputs_arrow as id and not probability_arrow, as you're building its id in the function as id + '_arrow' and you pass 'probability_inputs'.

I know that I'm a little late answering this, but I have a solution. There are two issues that should be addressed and they're as follows:
The ID of the last div is incorrect as stated in PSR's answer.
The check against the style attribute of the element in the toggleDiv method doesn't account for the lacking of the style attribute upon page load.
Regarding the first issue, the ID should read probability_inputs_arrow, which fixes the issue with the arrow not being updated when it is toggled. However, the second issue needs a little more explaining...
Upon page load, the CSS provided is applied to the elements with the IDs probability_inputs and start_conditions, giving them both a display value of none. Upon clicking on either one of these arrows, you're retrieving the style attributes of the targeted element, and checking the display property which upon page load is empty. This is why it requires two clicks to achieve the desired behaviour, because the first click is effectively just setting that value in the else statement.
Here's a link to an updated Codepen that contains the fixes: https://codepen.io/anon/pen/oweELy

actually you are getting error here
The second element need to have have probability_inputs_arrow as id and not probability_arrow,

The style.display is set to "" by default when the page loads for the first time, thus it ends up in the else block and then requires a second click to go to the if block. Just add this to your else if statement.
<script>
var x = document.getElementById("myDIV");
if (x.style.display == "none")
{
x.style.display = "block";
}
else if((x.style.display == 'null')||(x.style.display == ""))
{
x.style.display = "block";
}
else
{
x.style.display = "none";
}
</script>

I had this problem and it was due to the default state of the DIV. Even if you set the DIV class value is set display: none, it appears some browser do not accept this state, and therefore it is unknown.
To solve the problem, using your own code, add another condition of default:
var toggleDiv = function(id){
var tag = document.getElementById(id).style;
if(tag.display == 'none')
{
document.getElementById(id).style.display='block';
document.getElementById(id + '_arrow').className='arrow_down';
}
else if(tag.display == 'block')
{
document.getElementById(id).style.display='none';
document.getElementById(id + '_arrow').className='arrow_right';
}
else
{
document.getElementById(id).style.display='block';
document.getElementById(id + '_arrow').className='arrow_down';
}
};
`

Related

Cannot get element with the "display: none" property applied to it using getElementById()

I'm running into an issue where the getElementById() function is unable to get a particular element on the page that has the display: none property applied to it, even though it's visible in the DOM (I can see that the div and its id exists on the final rendered page).
Is there a way around this?
Here's the code:
togglePanel() {
const panelId = this.accordionItem.querySelector("#collapsible-panel");
this.shouldShowAccordion = !this.shouldShowAccordion;
if (this.shouldShowAccordion) {
panelId.classList.remove("collapsed");
}
else {
panelId.classList.add("collapsed");
}
}
"collapsible-panel" is the ID of the div which has display: none applied to it.
setTimeout(() => {
document.querySelector("div[id='collapsiblepanel']").style.display = 'block';
}, 2000)
#collapsiblepanel {
width: 200px;
height: 100px;
background-color: red;
display: none;
}
Following is ana example where I am selecting a div which has the value of display as none. After 2 seconds I am setting up it's display to block.
<div id="collapsiblepanel">
</div>

How do I make a <div> contentEditable on doubleclick using Svelte?

I'm brand new to Svelte (3.0+)...and for my latest project, I'd like to emulate the functionality of many "todo" lists that allow you to edit todo items previously submitted by double-clicking on them (Here's an example of the functionality I'm looking for).
I imagine, the first step is figuring out how to make a div contentEditable with Svelte with the on:dblclick event handler. I'm having trouble figuring out the syntax for this task (though I can do it with vanilla javascript).
Here's the Svelte code I have so far: ( Here it is on CodeSandBox.io - see page: CEDiv.svelte)
<script>
function edit(event) {
//update db functionality goes here
//alert("you've 'submitted' your edit")
}
function handleDblClick() {
//I need help HERE...and probably on the div on:dblclick down below....
}
function handleKeydown() {
key = event.key;
keyCode = event.keyCode;
//submit the div's content to the edit function if enter or tab is pressed.
keyCode == 13 || keyCode == 9 ? edit(event) : null;
}
</script>
<style>
div.read-mode {
padding:10px;
border:1px solid green;
height:30px;
line-height:30px;
width:500px;
margin:0 auto;
}
div.edit-mode {
padding:10px;
background: lightgreen;
border:3px solid green;
height:26px;
line-height:26px;
width:496px;
margin:0 auto;
}
</style>
<div on:dblclick={handleDblClick} class="read-mode" on:keydown={handleKeydown} contentEditable="false">
I want this Div to be editable one double click.
</div>
Thanks in advance for your help!
Add a boolean variable
let editable = false;
which will be changed inside your handler
function handleDblClick(event) {
editable = true; // or use editable=!editable to toggle
}
bind your editable variable inside the attribute,
and take a look how to dynamically toggle the class "edit-mode" using a ternary operator
<div
on:dblclick={handleDblClick}
class={editable ? 'edit-mode': 'read-mode'}
on:keydown={handleKeydown}
contenteditable={editable}>
I want this Div to be editable on double click.
</div>
Here's a CodeSandbox fork

Place a button and its div with one command

Currently, I have a button class which lets me place a clickable button inside a sentence, and a div class which lets me add content to the button which I placed at the end of the paragraph containing the sentence.
This is an example of how I use them
Try to click <button class="col">THIS</button> and see what happens.
<div class="con">nice!</div>
Did you try?
When this text is displayed on the page, the two sentences are placed inside two different paragraphs, so the div object is placed between them.
Here is a snippet with the css classes and the javascript.
( function() {
coll = document.getElementsByClassName("col");
conn = document.getElementsByClassName("con");
var i;
for (i = 0; i < coll.length; i++) {
coll[i].setAttribute('data-id', 'con' + i);
conn[i].setAttribute('id', 'con' + i);
coll[i].addEventListener("click", function() {
this.classList.toggle("active");
var content = document.getElementById(this.getAttribute('data-id'));
if (content.style.maxHeight) {
content.style.maxHeight = null;
} else {
content.style.maxHeight = content.scrollHeight + "px";
}
});
}
} )();
.col {
cursor: help;
border-radius: 0;
border: none;
outline: none;
background: none;
padding: 0;
font-size: 1em;
color: red;
}
.con {
padding: 0 1em;
max-height: 0;
overflow: hidden;
transition: .3s ease;
background-color: yellow;
}
Try to click <button class="col">THIS</button> and see what happens.
<div class="con">nice!</div>
Did you try?
I wonder if it is possible to implement a shortcut to place the two objects with one command, that is to obtain the previous example by using something like this
Try to click [[THIS|nice!]] and see what happens.
Did you try?
What I mean is that the command [[THIS|nice!]] should place the object <button class="col">THIS</button> in the same position and the object <div class="con">nice!</div> at the end of the paragraph containing the command.
Is it possible to implement such a command (or a similar one)?
EDIT
I forgot to say that the content of the button, ie what is written inside the div, should also be possible to be a wordpress shortcode, which is a shortcut/macro for a longer piece of code or text.
Using jQuery, closest() find the nearest <p> element and add <div class="con">nice!</div> after <p> element. To toggle you can use class active and add or remove .con element.
$('.col').click(function(){
let traget = $(this).closest('p');
if(traget.hasClass('active')) {
traget.removeClass('active');
traget.next('.con').remove();
} else {
traget.addClass('active');
traget.after(`<div class="con">${$(this).data('message')}</div>`);
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<p>Try to click <button class="col" data-message="Hello">THIS</button> and see what happens.</p>
<p>Did you try?</p>
You usually dont use div to type text. you use it to define areas or group items. you could obtain what youre asking for in a 1 sentence like this:
html
<h1> some random text <a class="btnID">button</> some more text<h1>
css
.btnID {
color: red;
}

Semantic element to create a toggle and best practice to undo a function

Sample:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Toggle</title>
<style>
#first {
color: blue;
}
#second {
border: 1px solid green;
}
#third {
background: tan;
}
</style>
</head>
<body>
<label for="box">Toggle</label>
<input type="checkbox" id="box" onchange="toggle();">
<div id="first">First</div>
<div id="second">Second</div>
<div id="third">Third</div>
<script>
function toggle() {
var box = document.getElementById('box');
var first = document.getElementById('first');
var second = document.getElementById('second');
var third = document.getElementById('third');
if (box.checked) {
first.style.color = 'red';
second.style.border = '2px dotted blue';
third.style.background = 'olive';
} else {
first.style.color = 'blue';
second.style.border = '1px solid green';
third.style.background = 'tan';
}
}
</script>
</body>
</html>
DEMO
I wonder if an input checkbox is the right element to create a toggle. I also want to know how to undo what I have in the if clause: in else do I have to repeat my stylesheet or is there a shorter neater way to get back to the initial state?
You can do it in better way like this: demo
Add a parent div in html like this:
<div id="parent">
<div id="first">First</div>
<div id="second">Second</div>
<div id="third">Third</div>
</div>
Then handle your front end with css instead inline styling:
.checked #first {
color:red;
}
.checked #second {
border:2px dotted blue;
}
.checked #third {
background:olive;
}
Then add and remove only one class with javascript:
function toggle() {
var box = document.getElementById('box');
var parent = document.getElementById('parent');
if (box.checked) {
parent.className = parent.className + "checked";
} else {
parent.className = "";
}
}
1. I wonder if an input checkbox is the right element to create a toggle?
Definition of toggle*:
COMPUTING a key or command that is operated the same way but with
opposite effect on successive occasions.
Explanation of checkbox**:
In computing, a checkbox (check box, tickbox, or tick box) is a
graphical user interface element (widget) that permits the user to
make a binary choice, i.e. a choice between one of two possible
mutually exclusive options.
So yes, it is the best choice.
2. I also want to know how to undo what I have in the if clause: in else do I have to repeat my stylesheet or is there a shorter neater way to get back to the initial state?
In order to do this you could using jQuery:
Use either addClass()/removeCLass() methods or toggleClass(); You would put your active class stylings into a new class, apply these then simply remove them on the else/off state. This would also mean you maintain the separation between contents and styling.
Or regular JS:
.setAttribute("class", "active"); and .removeAttribute("class", "active"); or simply .removeAttribute("style"); to unset the styles you applied inline and revert to the original state.
*Source
**Source
To answer the second question:
You could use getElementById("id").removeAttribute("style"); to remove inline styles.
if (box.checked) {
first.style.color = 'red';
second.style.border = '2px dotted blue';
third.style.background = 'olive';
} else {
first.removeAttribute("style")
second.removeAttribute("style")
third.removeAttribute("style")
}

Created div elements' random margins not working

Problem and source code
I'm trying to create <div>s within another <div> at the click of a button. When the button is clicked, a new inner <div> is created (within the outer <div>) with a unique id. I have this part working but here's where I'm running into an issue: I want each inner <div> to have a random margin-top.
Javascript
function pressButton() {
number += 1;
makeDiv(number);
};
function makeDiv(x) {
var innerDiv = document.createElement("innerDiv" + x);
outer.appendChild(innerDiv);
innerDiv.setAttribute("style", "margin-top:" + Math.floor(Math.random()*51) + ";display:inline-block;width:48px;height:48px;background-color:#000;");
};
CSS:
#outer {
position:absolute;
white-space:nowrap;
height:118px;
overflow:auto;
width:100%;
padding:2px;
}
Result (after button is clicked 4 times)
<div id="outer">
<innerDiv1 style="margin-top:15;display:inline-block;width:48px;height:48px;background-color:#000;"></innerDiv1>
<innerDiv2 style="margin-top:23;display:inline-block;width:48px;height:48px;background-color:#000;"></innerDiv2>
<innerDiv3 style="margin-top:37;display:inline-block;width:48px;height:48px;background-color:#000;"></innerDiv3>
<innerDiv4 style="margin-top:0;display:inline-block;width:48px;height:48px;background-color:#000;"></innerDiv4>
</div>
The result (which I got from inspecting the inner elements in my browser) looks like everything worked - all the margin-tops are random like I wanted. However, the visual result is this:
As you can see, the black inner <div>s all have the same margin-top. What am I doing wrong? How can I make the created <div>s all have random margin-tops?
The CSS spec requires that a length (other than zero) that is missing a unit be treated as an error (and thus ignored). Therefore, add px to the end of your generated margin number, and all should be well.
Live Demo
Description
This happens, because you set the display:inline-block; property. This makes them all to be in one line, so they will allign to the innerDivx that has the highest margin-top.
Delete the display:inline-block; property and give them float:left;. If you want to keep the gap between them, also add margin-left:5px;. And don't forget that margin-top's value needs a unit. I think you wanted to use px.
Also <innerDivx> is not a valid HTML tag. You should change them to a <div> and use innerDivx as an id attribute. Also your tags use almost the same CSS styles so you should put the same ones to a class and add the class instead.
Full solution code
HTML
<button id="button1">Add box</button>
<div id="outer"></div>
JavaScript
var number = 0;
document.getElementById("button1").addEventListener("click", pressButton, false);
function pressButton() {
++number;
makeDiv(number);
};
function makeDiv(x) {
var innerDiv = document.createElement("div");
outer.appendChild(innerDiv);
innerDiv.className += " box";
innerDiv.setAttribute("id", "innerDiv" + x);
innerDiv.setAttribute("style", "margin-top:" + Math.floor(Math.random()*51) + "px;");
};
CSS
#outer {
position: absolute;
white-space: nowrap;
height: 118px;
overflow: auto;
width: 100%;
padding: 2px;
}
.box {
float: left;
width: 48px;
height: 48px;
background-color: #000;
margin-left: 5px;
}
This is likely caused by the position model used for inline-block elements - they're all being vertically-aligned at their bottom line in a row.
I suggest that you simplify this and use position: block with float: left
http://jsfiddle.net/2y5bJ/4/
I also suggest that you stick to standard elements to ensure cross-browser compatibility - don't create your own elements called innerDiv1 etc, but use div elements with unique IDs.
function makeDiv(x) {
var innerDiv = document.createElement("div");
outer.appendChild(div);
innerDiv.setAttribute('id', 'innerDiv' + x);
innerDiv.setAttribute("style", "margin-top:" + Math.floor(Math.random()*51) + "px;");
};
I think there is no tag available with name
<innerDiv1>
This may be the cause.

Categories