Accessing parentNode with button - javascript

I am trying to access the parentNode of a button element (div) but I get an error every time. Here is what I am trying to do. Simply put, this is a page that had 2 divs on it. I only want one div displayed at a time. There is a button on the first page that switches to the second and a button on the second that is supposed to return to the first (but doesn't because it can't locate the parentNode).
<div class="pageContent" id="page_3">
<div class="primaryPage" id="primaryPage_3">
<h2>Bills_______________________</h2>
<p>Here are my monthly Bills<br><br>blah blah</p>
<button type="button" id="billButton" onclick="newBill()">Add Bill</button>
</div>
<div class="pageContent" id="billPage">
<p>this is the bill page</p>
<button class="backButton" onclick="back()">Back</button>
</div>
</div>
function newBill(){
document.getElementById("primaryPage_3").style.display = "none";
document.getElementById("billPage").style.display = "block";
document.getElementById("billPage").setAttribute("back", "primaryPage_3");
}
function back(){
var previousPage = this.parentNode.getAttribute("back");
this.parentNode.style.display = "none";
document.getElementById(previousPage).style.display = "block";
}

Change this...
onclick="back()"
to this...
onclick="back.call(this)"
Invoking a function using .call() lets you manually set the calling context (the this value) of the function being invoked. Here it's setting it to the current element.

Related

How do i make one button content close when i click another button's content in Javascript

My problem is that I have a website, using javascript I have made it when I click on the About Me it opens, but when I click on Education and Achievements the About me button's content remains open and the Education stuff overlaps it. I want to make it so that when I click on another button the first one closes (its content. The website name is dirieahmed.ml
My code HTML and JS will be linked below ill add CSS later if need be.
<div class="container">
<button id="one" class="click one">About Me</button>
<div class="list-1 sec">
<h1 class="content-header-one content">Dummy text header</h1>
<p class="content-paragraph-one">Dummy text</p>
</div>
<button class="click two">Education and Achivements</button>
<div class="list-2 sec">
<p class="content-paragraph2 content">Dummy text</p>
<ul class="content-list content">
<li>- Achivement #1</li>
<li>- Achivement #2</li>
<li>- Achivement #3</li>
</ul>
</div>
<button class="click three" >Other</button>
<div class="list-3 sec">
<h1 class="content-header-two content">Dummy text header</h1>
<p class="content-paragraph3 content">Dummy text</p>
</div>
<script async>
let one = document.querySelector('.one');
let two = document.querySelector('.two');
let three = document.querySelector('.three');
let list1 = document.querySelector('.list-1');
let list2 = document.querySelector('.list-2');
let list3 = document.querySelector('.list-3');
one.addEventListener("click", ()=>{
list1.classList.toggle('newlist');
});
two.addEventListener("click", ()=>{
list2.classList.toggle('newlist');
lis
})
three.addEventListener("click", ()=>{
list3.classList.toggle('newlist')
});
// please change above
</script>
</div>
To summarize you will need to hide all other ones when there is a click anywhere and then only show the ones based on the link that you clicked
Check the code below
https://codesandbox.io/s/keen-driscoll-igzlwb?file=/index.html:2333-3356
<script async>
// Instanciate List div's
let list1 = document.querySelector(".list-1");
let list2 = document.querySelector(".list-2");
let list3 = document.querySelector(".list-3");
// Reset's all views to the default without .newlist
const resetAllViews = () => {
list1.classList.remove("newlist");
list2.classList.remove("newlist");
list3.classList.remove("newlist");
};
// Checks to see what button is clicked and shows correct list based on input
document.addEventListener(
"click",
function (e) {
e = e || window.event;
var target = e.target;
if (target.classList.contains("one")) {
resetAllViews();
list1.classList.add("newlist");
}
if (target.classList.contains("two")) {
resetAllViews();
list2.classList.add("newlist");
}
if (target.classList.contains("three")) {
resetAllViews();
list3.classList.add("newlist");
}
}, false);
</script>
The document object should be given a click event listener.
Use the contains() function to determine with each click if the clicked element is outside the targeted element.
Hide the original element if the clicked element is outside.

Change a div on click of button

I am new to front-end. Now, Here I have 3 divs which will be on the same page.and the position will also be same. it is like toggling .
So at the start this will be the div that I will show
<div text-angular id="htmlEditorId" >Abc</div>
then there is button whick is like
<button class="col-xs-3 btn btn-default" ng-click="changeTab()">NextTab </button>
On click of that button
<div text-angular id="secon">abcd</div>
this div should be shown and not the previous one.
And on again click of that button a third div
<div text-angular id="third">azzzbcd</div>
this should be seen and again on click first one should show . Its like a round robin fashion .
Now what I tried is using ng-show and ng-if. Can any one help me with this?
$scope.changeTab = function() {
$scope.showfirst = true;
$scope.showsecond = false;
}
It's quite simple, you can do it in many ways, for example:
In the controller
Define a scoped variable (bindable with the front-end)
$scope.showView = "firstView"
Define also a function:
$scope.changeView = function(value) {
$scope.showView = value;
}
In the html page define your divs and button
<button ng-click="changeView('secondView')">Chage View</button>
<div ng-show="showView == 'firstView'">abcd</div>
<div ng-show="showView == 'secondView'">abcd</div>

Get clicked element's ID and include it in a function with pure JS?

I need to display different output according to each different icon clicked without defining separate functions;
HTML:
<p onclick="expand()" id="i1">icon1</p>
<p onclick="expand()" id="i2">icon2</p>
<p onclick="expand()" id="i3">icon3</p>
<div id="blocki1"></div>
<div id="blocki2"></div>
<div id="blocki3"></div>
Can I do something like this with JS?
function expand() {
document.getElementById("block" + this.id).style.display = "block";
}
I've tried the method above which apparently didn't work, I need to a)store icon's id and b) combine the id with string. Don't sure if that's possible.
<p onclick="expand(this.id) id="i1">icon1</p>
<p onclick="expand(this.id) id="i2">icon2</p>
<p onclick="expand(this.id) id="i3">icon3</p>
<div id="blocki1"></div>
<div id="blocki2"></div>
<div id="blocki3"></div>
<script>
function expand(e) {
document.getElementById("block" + e).style.display = "block";
}}
</script>
First.. You have 4 typos. First 3 are that you don't have closing " after onclick="expand()
<p onclick="expand() id="i1">icon1</p>
<!-- There needs to be " after expand() -->
Last typo is you have extra closing } after expand function.
Now, since you're not using addEventListener API, the value of this will not be set on your expand function.
So you need to pass your current element as a parameter to the function.
<p onclick="expand(this)" id="i1">icon1</p>
<p onclick="expand(this)" id="i2">icon2</p>
<p onclick="expand(this)" id="i3">icon3</p>
<div id="blocki1">blocki1</div>
<div id="blocki2">blocki2</div>
<div id="blocki3">blocki3</div>
(Added some place holder text to divs to see if this works)
Lastly, access the current element in your function as a first parameter.
function expand(el) {
document.getElementById("block" + el.id).style.display = "block";
}
Pass parameters to the function
You need to pass some data (e.g. the reference to the object, its name, or whatever else you need) to the function you're calling.
For example, look at the sample code from https://www.w3schools.com/jsref/event_onclick.asp
<p onclick="myFunction(this, 'red')">Click me to change my text color.</p>
<script>
function myFunction(elmnt,clr) {
elmnt.style.color = clr;
}
</script>
I might approach it slightly differently by removing the inline JS, and using classes and data attributes. Here I have classes and data attributes on all the elements. I attach click event listeners to the "buttons" which call the handleClick function. This function checks the data id attribute of the button and grabs the corresponding slide, adding a "show" class to its class list.
const buttons = document.querySelectorAll('.button');
buttons.forEach(button => {
button.addEventListener('click', handleClick, false);
});
function handleClick(e) {
const id = e.target.dataset.id;
const slide = document.querySelector(`.slide[data-id="${id}"]`);
slide.classList.add('show');
}
.slide {
display: none;
}
.show {
display: block;
}
<p class="button" data-id="1">icon1</p>
<p class="button" data-id="2">icon2</p>
<p class="button" data-id="3">icon3</p>
<div class="slide" data-id="1">blocki1</div>
<div class="slide" data-id="2">blocki2</div>
<div class="slide" data-id="3">blocki3</div>
Your code should like this
<p onclick="expand(this) id="i1">icon1</p>
<p onclick="expand(this) id="i2">icon2</p>
<p onclick="expand(this) id="i3">icon3</p>
<div id="blocki1"></div>
<div id="blocki2"></div>
<div id="blocki3"></div>
<script>
function expand(elm) {
document.getElementById("block" + elm.id).style.display = "block";
}
</script>
If you are a beginner, I would suggest you to avoid practice of adding handlers in HTML, before it becomes your coding attitude.
Instead, add eventlisteners for them in js. Separation of concerns is really big theory.
And it's relativelyeasy to deal with this in event handlers
You can read more about it here
var ps = Array.from(document.querySelectorAll("p"));
for(var i=0; i< ps.length; i++){
ps[i].addEventListener(("click"), function(){
document.getElementById("block" + this.id).style.display = "block";
})
}
div{
display: none;
}
<p id="i1">icon1</p>
<p id="i2">icon2</p>
<p id="i3">icon3</p>
<div id="blocki1">This is 1</div>
<div id="blocki2">This is 2</div>
<div id="blocki3">This is 3</div>

Javascript hide/show with many elements

in my HTML i have questions and solutions. I want to hide and show solutions for each question with different buttons.
Here is my problem: I am writing a new function for each solution button. For example if i have 100 questions then i need to write 100 different Javascript function.
Is there any better way for doing this. Can i write only one function for each solution button.
Thank you very much in advance.
Here is my html:
<li>Question 1. What is x?</li>
<button class="btn btn-outline-success"
onclick="myFunction()">Solution</button>
<div id="Solution">
<div class="highlight">
<pre>
X is apple
</pre>
<li>Question 2. What is y?</li>
<button class="btn btn-outline-success"
onclick="myFunction1()">Solution</button>
<div id="Solution1">
<div class="highlight">
<pre>
Y is orange
</pre>
And here is my Javascript:
document.getElementById( 'Solution' ).style.display = 'none';
function myFunction() {
var x = document.getElementById('Solution');
if (x.style.display === 'none') {
x.style.display = 'block';
} else {
x.style.display = 'none';
}
}
document.getElementById( 'Solution1' ).style.display = 'none';
function myFunction1() {
var x = document.getElementById('Solution1');
if (x.style.display === 'none') {
x.style.display = 'block';
} else {
x.style.display = 'none';
}
}
Note:I saw many questions about hide and show but i could not solve my problem. If this is a duplicate question please warn me and i can remove.
You can reuse a single function by passing an argument that identifies which element in the document should be shown/hidden:
document.getElementById( 'Solution' ).style.display = 'none';
// The function now expects to be passed the ID of the element
function myFunction(elementID) {
var x = document.getElementById(elementID);
if (x.style.display === 'none') {
x.style.display = 'block';
} else {
x.style.display = 'none';
}
}
Now, you can call the function repeatedly and just pass different element id's each time:
<li>Question 1. What is x?</li>
<button class="btn btn-outline-success" onclick="myFunction('Solution')">Solution</button>
<div id="Solution">
<div class="highlight">
<pre>X is apple</pre>
</div>
</div>
<li>Question 2. What is y?</li>
<button class="btn btn-outline-success" onclick="myFunction('Solution1')">Solution</button>
<div id="Solution1">
<div class="highlight">
<pre>Y is orange</pre>
</div>
</div>
Now, having said that, you should avoid using inline HTML event attributes (onclick, onmouseover, etc.) whenever possible. There are many reasons why. Additionally, instead of repeatedly setting inline styles, you can make this much simpler by toggling the use of a pre-existing CSS class. Also, your HTML syntax is invalid.
Here's what a cleaned up, valid and modern version of your code would look like. All you have to do is copy the HTML structure of a question and the existing JavaScript will immediately work for it. Each question no longer even needs a name ("Solution1", "Solution2", etc.).
// Get all the buttons in a node list
var theButtons = document.querySelectorAll(".btn-outline-success");
// Turn node list into a JS Array
var buttonArray = Array.from(theButtons);
// Loop over the buttons and give each its click event handler
buttonArray.forEach(function(button){
button.addEventListener("click", function(){
// We will pass a reference to the current button to the function
myFunction(this);
});
});
// The function now expects to be passed a reference to the button that was clicked
function myFunction(element) {
// Get a reference to div that follows the button and then search that div
// for the first pre element inside of it:
var answer = element.nextElementSibling.querySelector("pre");
// All we need to do is toggle the visibility of that pre element
answer.classList.toggle("hidden");
}
/* This class will simply be added or removed to show/hide elements */
/* All answers have this applied by default*/
.hidden {
display:none;
}
li { margin-bottom:10px; }
<!--
NOTES:
1. The onclick has been removed (it is now handled in JavaScript)
2. The quesiton names ("Solution", "Solution1", etc.) are no longer needed
3. Your HTML structure was invalid. Here is the proper way to make bulleted lists.
-->
<ul>
<li>Question 1. What is x?
<button class="btn btn-outline-success">Solution</button>
<div>
<div class="highlight">
<pre class="hidden">X is apple</pre>
</div>
</div>
</li>
<li>Question 2. What is y?
<button class="btn btn-outline-success">Solution</button>
<div>
<div class="highlight">
<pre class="hidden">Y is orange</pre>
</div>
</div>
</li>
<li>Question 3. What is z?
<button class="btn btn-outline-success">Solution</button>
<div>
<div class="highlight">
<pre class="hidden">z is mango</pre>
</div>
</div>
</li>
</ul>
If I understood what you want, you can use parameters.
HTML
<li>Question 1. What is x?</li>
<button class="btn btn-outline-success" onclick="myFunction(1)">Solution</button>
<div id="Solution"></div>
<div class="highlight"></div>
<pre>
X is apple
</pre>
JS
function myFunction(var solNumber = 1) {
var x = document.getElementById('Solution'+solNumber);
if (x.style.display === 'none') {
x.style.display = 'block';
} else {
x.style.display = 'none';
}
}
If all the questions appear in the same time, you could use a for loop to show them all too.
You can do something like this:
Enclose the question in a div with class 'question' and similarly solution enclosed with class 'solution'.
Also define a single show function with parameter as the button element clicked, which passed by using this as parameter in the onclick of button.
The function simply finds the sibling div with class 'solution' and makes it visible by setting display: block
function show_solution(buttonElement) {
questionDiv = buttonElement.parentNode;
if (questionDiv.querySelector('.solution').style.display == 'none') {
questionDiv.querySelector('.solution').style.display = 'block';
} else {
questionDiv.querySelector('.solution').style.display = 'none';
}
}
.solution {
display: none;
}
.highlight {
background: #FF0;
}
<div class="question">
• Question 1. What is x?
<button class="btn btn-outline-success" onclick="show_solution(this)">Solution</button>
<div class="solution">
<div class="highlight">
<pre> X is apple </pre>
</div>
</div>
</div>
<div class="question">
• Question 2. What is y?
<button class="btn btn-outline-success" onclick="show_solution(this)">Solution</button>
<div class="solution">
<div class="highlight">
<pre> Y is orange </pre>
</div>
</div>
</div>
Well, if jquery was allowed, the solution could look like this:
$('.Solution').hide()
$('button').on('click',function(){$(this).next().show()})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<li>Question 1. What is x?</li>
<button class="btn btn-outline-success">Solution</button>
<div class="Solution">
<div class="highlight">
<pre>
X is apple
</pre>
</div></div>
<li>Question 2. What is y?</li>
<button class="btn btn-outline-success">Solution</button>
<div class="Solution">
<div class="highlight">
<pre>
Y is orange
</pre>
</div></div>
Note: this would also simplify your html ... But, of course, the choice is yours!

Flip divs using a function

I'm new with javascript and I have a tiny problem.
I want to create a function and by pressing that button to invert the two divs ( the first one to be placed second and viceversa). I hope you understand.
I have this code:
<div> text 1 </div>
<div> text 2 </div>
<button> invert </button>
Using pure javascript, you can simply switch the contents of each div:
function flip(){
div1_content = document.getElementById("div1").innerHTML;
div2_content = document.getElementById("div2").innerHTML;
document.getElementById("div1").innerHTML = div2_content;
document.getElementById("div2").innerHTML = div1_content;
}
<div id="div1"> Text 1 </div>
<div id="div2"> Text 2 </div>
<button onclick="flip()"> Flip it! </button>
We're simply storying the contents of each div, then assigning them to one another. Hopefully, you can take this, learn from it, and apply it how you intend to.
Here is a simple javascript solution
jsFiddle https://jsfiddle.net/xzLme043/2/
myFunction = function(){
var div1 = document.getElementById('one');
var div2 = document.getElementById('two');
var html = div1.innerHTML;
div1.innerHTML = div2.innerHTML;
div2.innerHTML = html;
};
For this solution, you'll just place the current two divs in another parent div container, and then just insert the second div before the first, on the click of the invert button. No changing or pulling of inner text or HTML required.
function invertDivs(parentDiv) {
var first = document.getElementById(parentDiv).firstElementChild;
console.log(first);
var second = document.getElementById(parentDiv).lastElementChild;
console.log(second);
document.getElementById(parentDiv).insertBefore(second, first);
}
<div id="parent">
<div id="first">div 1</div>
<div id="second">div 2</div>
</div>
<button onclick="invertDivs('parent');">invert</button>

Categories