Here is the method Iβm trying to make. Basically what itβs supposed to do is, when an <input> with the type of button is clicked, it makes the next <div> (in this case hard-coded) go from display: none to display: block. However itβs not working.
matchDivs() {
let showInputs = document.querySelectorAll('input')
const inputs = Array.from(showInputs)
inputs.map(input => {
if (input.parentNode.getAttribute('class') === 'first-employee') {
document.querySelector('.second-employee').setAttribute('style', 'display: block')
}
return input
})
}
When you use if (node.getAttribute('class') === 'first-employee') this is return:
class='first-employee' // true
class='employee first-employee' // false
You must use:
if (node.classList.contains("first-employee")):
class='first-employee' // true
class='employee first-employee' // true
If I have understand your question properly that on button click you want to show/hide DIV tag next to it, which is inside common parent div for both, button and 'second-employee'.
I think below will be helpful.
// For single Div show/hide on button click
let btnMatchDiv = document.querySelector('#btnMatchDivs');
btnMatchDiv.addEventListener('click', matchDivs, true);
function matchDivs() {
let showInputs = document.querySelectorAll('input')
const inputs = Array.from(showInputs)
inputs.map(input => {
// Method 1
// ===========================
/*if (input.parentNode.getAttribute('class') === 'first-employee') {
document.querySelector('.second-employee').setAttribute('style', 'display: block')
}*/
// Method 2 : you can use new classList method
// ===========================
if (input.parentNode.classList.contains('first-employee')) {
input.nextElementSibling.classList.toggle('hidden');
}
//return input
})
}
body {
font-family: Arial;
}
.first-employee {
display: block;
padding: 1em;
border: 1px solid green;
}
.second-employee {
padding: 1em;
border: 1px solid red;
}
#btnMatchDivs {
padding: 1em 0.5em;
border: 1px solid #777;
}
.hidden {
display: none
}
<div class="first-employee">
<h2>
First Employee
</h2>
<input type="button" id="btnMatchDivs" value="Toggle Second Employee" />
<div class="second-employee hidden">
Second Employee
</div>
</div>
Please let me know if you need further help on this.
Thanks,
Jignesh Raval
Also if you want to toggle multiple items then you can try below code.
// For multiple Div show/hide on button click
// ===================================
let showInputs = document.querySelectorAll('input')
const btnInputs = Array.from(showInputs)
// Bind click event to each button input
btnInputs.map(input => {
input.addEventListener('click', matchDivs, false);
})
function matchDivs(event) {
let buttonEle = event.currentTarget;
if (buttonEle.parentNode.classList.contains('first-employee')) {
buttonEle.nextElementSibling.classList.toggle('hidden');
}
}
body {
font-family: Arial;
}
.first-employee {
display: block;
padding: 1em;
border: 1px solid green;
margin-bottom: 1em;
}
.second-employee {
margin: 1em 0;
padding: 1em;
border: 1px solid red;
}
#btnMatchDivs {
padding: 1em 0.5em;
border: 1px solid #777;
}
.hidden {
display: none
}
<div class="first-employee">
<h2>
First Employee 1
</h2>
<input type="button" id="btnMatchDivs" value="Match Divs" />
<div class="second-employee hidden">
Second Employee 1
</div>
</div>
<div class="first-employee">
<h2>
First Employee 2
</h2>
<input type="button" id="btnMatchDivs" value="Match Divs" />
<div class="second-employee hidden">
Second Employee 2
</div>
</div>
<div class="first-employee">
<h2>
First Employee 3
</h2>
<input type="button" id="btnMatchDivs" value="Match Divs" />
<div class="second-employee hidden">
Second Employee 3
</div>
</div>
I hope this will be helpful.
Thanks,
Jignesh Raval
Related
I can't figure out how to close one submenu when another one is open. I'm not sure if html is needed here, so I'm just attaching JS code here:
const burgerBtn = document.querySelector(".header__burger"),
menu = document.querySelector(".menu"),
body = document.querySelector(".body"),
filter = document.querySelector(".filter"),
blockFilter = document.querySelectorAll(".block-filter"),
dropdown = document.querySelectorAll(".block-filter__dropdown");
if (filter) {
blockFilter.forEach(item => {
item.addEventListener("click", event => {
item.querySelector(".block-filter__dropdown").classList.toggle("block-filter__dropdown_state_active");
item.querySelector(".block-filter__icon").classList.toggle("block-filter__icon_state_active");
if (event.target.classList.contains("block-filter__item")) {
item.querySelector(".block-filter__value").textContent = event.target.textContent;
}
})
})
}
<div class="filter hero__filter">
<form class="filter__form">
<div class="filter__block block-filter">
<div class="block-filter__button">
<div class="block-filter__header">
<span class="block-filter__type">Purpose</span>
<div class="block-filter__icon"></div>
</div>
<span class="block-filter__value">Buy</span>
</div>
<div class="block-filter__dropdown">
<span class="block-filter__item">Buy</span>
<span class="block-filter__item">Sell</span>
</div>
</div>
Sure, just remove the class from the active one first:
item.addEventListener("click", (event) => {
// get active, and if it exists, remove active
document.querySelector(".block-filter__dropdown_state_active")?.classList.remove("block-filter__dropdown_state_active");
item.querySelector(".block-filter__dropdown").classList.toggle(
"block-filter__dropdown_state_active"
);
item.querySelector(".block-filter__icon").classList.toggle(
"block-filter__icon_state_active"
);
if (event.target.classList.contains("block-filter__item")) {
item.querySelector(".block-filter__value").textContent =
event.target.textContent;
}
});
We use ?. here to prevent us from going further (and causing an error) if there is no active dropdown already.
What you need to do is look for a currently active item first and "de-activate" them. You should also check that the currently active item is not the clicked item as you already have logic defined for that.
I've expanded on your snippet to create a solution.
NOTE: It might be useful creating a separate function/s for handling to "activate" and "de-activate" code where you pass in a .block-filter element.
const burgerBtn = document.querySelector(".header__burger"),
menu = document.querySelector(".menu"),
body = document.querySelector(".body"),
filter = document.querySelector(".filter"),
blockFilter = document.querySelectorAll(".block-filter"),
dropdown = document.querySelectorAll(".block-filter__dropdown");
if (filter) {
blockFilter.forEach(item => {
item.addEventListener("click", event => {
const active_dropdown = document.querySelector(".block-filter__dropdown_state_active");
if(active_dropdown !== null){
// get parent until we find ".block-filter"
const active_item = active_dropdown.closest(".block-filter");
// check it's not the current item
if(active_item !== null && active_item !== item){
// apply same logic as below to remove active state
active_item.querySelector(".block-filter__dropdown").classList.remove("block-filter__dropdown_state_active");
active_item.querySelector(".block-filter__icon").classList.remove("block-filter__icon_state_active");
}
}
// your original logic
item.querySelector(".block-filter__dropdown").classList.toggle("block-filter__dropdown_state_active");
item.querySelector(".block-filter__icon").classList.toggle("block-filter__icon_state_active");
if (event.target.classList.contains("block-filter__item")) {
item.querySelector(".block-filter__value").textContent = event.target.textContent;
}
})
})
}
/* base styles */
* {
box-sizing: border-box;
}
html {
font-family: sans-serif;
background-color: #f3f3f3;
}
.filter.hero__filter {
width:600px;
margin:auto;
border: 2px solid #eee;
background-color: #fff;
}
.filter__form {
display:flex;
}
.filter__block {
flex: 1;
padding: 5px;
position: relative;
}
.block-filter__header {
font-weight:600;
font-size:12px;
color: #555;
}
.block-filter__dropdown {
display:none;
position:absolute;
top:100%;
left:0;
right:0;
background-color:#fff;
border: 1px solid #ccc;
box-shadow: 0 2px 4px rgb(0 0 0 / 10%);
border-radius:4px;
}
.block-filter__dropdown_state_active {
display: block;
}
.block-filter__item {
padding: 5px 10px;
display:block;
border-bottom: 1px solid #eee;
}
.block-filter__item:last-child {
border-bottom: none;
}
<div class="filter hero__filter">
<form class="filter__form">
<div class="filter__block block-filter">
<div class="block-filter__button">
<div class="block-filter__header">
<span class="block-filter__type">Purpose</span>
<div class="block-filter__icon"></div>
</div>
<span class="block-filter__value">Buy</span>
</div>
<div class="block-filter__dropdown">
<span class="block-filter__item">Buy</span>
<span class="block-filter__item">Sell</span>
</div>
</div>
<div class="filter__block block-filter">
<div class="block-filter__button">
<div class="block-filter__header">
<span class="block-filter__type">Second</span>
<div class="block-filter__icon"></div>
</div>
<span class="block-filter__value">Alpha</span>
</div>
<div class="block-filter__dropdown">
<span class="block-filter__item">Bravo</span>
<span class="block-filter__item">Charlie</span>
<span class="block-filter__item">Delta</span>
</div>
</div>
</form>
</div>
i have added button that creates multiple year i want to stop creation of field when number of year is 10. how can i stop this. on year 10?
also i want to disable button once year 10 field is created.
let i = 2;
document.getElementById('add-new-person').onclick = function () {
let template = `
<h3>Year ${i}:</h3>
<p>
<input name="people[${i}][first_name]">
</p>
`;
let container = document.getElementById('people-container');
let div = document.createElement('div');
div.innerHTML = template;
container.appendChild(div);
i++;
}
body {
padding: 2em;
}
[type=submit] {
padding: 0.5em 2em;
}
.add-new-person {
background: #6688dd;
border-radius: 0.25em;
color: #fff;
display: inline-block;
padding: 0.5em;
text-decoration: none;
}
<form method="post">
<div id="people-container">
<h3>Year 1:</h3>
<p>
<input name="people[1][first_name]">
</p>
</div>
Add! new year
<p>
<input type="submit" value="Save">
</p>
</form>
You can use button element instead of a tag. This works better then an a tag. Also, to prevent default behavior of button click we use preventDefault() method. So our page is not reloading each time we click.
To disable your button just set the button attr to disabled to true when the limit reaches years > 10
I have added comments in each line to reflects what happening as well.
Run snippet below to see it working.
//Button
let button = document.getElementById('add-new-person')
//Limit of elements
let i = 2;
//Click function
button.onclick = function(e) {
//Disable default behabviour
e.preventDefault()
//Appending extra years
let template = `
<h3>Year ${i}:</h3>
<p>
<input name="people[${i}][first_name]">
</p>`;
//Checking if the limit is > 10 then we are disabling the button
if (i > 10) {
//Disable button
button.disabled = true;
console.log('Button Disabled')
//Return false
return;
} else {
let container = document.getElementById('people-container');
let div = document.createElement('div');
div.innerHTML = template;
container.appendChild(div);
i++;
}
}
body {
padding: 2em;
}
[type=submit] {
padding: 0.5em 2em;
}
.add-new-person {
background: #6688dd;
border-radius: 0.25em;
color: #fff;
display: inline-block;
padding: 0.5em;
text-decoration: none;
}
<form method="post">
<div id="people-container">
<h3>Year 1:</h3>
<p>
<input name="people[1][first_name]">
</p>
</div>
<button id="add-new-person" class="add-new-person">Add! new year</button>
<p>
<input type="submit" value="Save">
</p>
</form>
I hope it is useful
let i = 2;
document.getElementById('add-new-person').onclick = function () {
//check it if i<=10 do it
if(i <=10){
let template = `
<h3>Year ${i}:</h3>
<p>
<input name="people[${i}][first_name]">
</p>
`;
let container = document.getElementById('people-container');
let div = document.createElement('div');
div.innerHTML = template;
container.appendChild(div);
i++;
}
//if i>10 add deactive class to element
else{
document.getElementById("add-new-person").classList.add("Deactive");
}
}
body {
padding: 2em;
}
[type=submit] {
padding: 0.5em 2em;
}
.add-new-person {
background: #6688dd;
border-radius: 0.25em;
color: #fff;
display: inline-block;
padding: 0.5em;
text-decoration: none;
}
.add-new-person.Deactive{
background: gray;
cursor: not-allowed;
}
<form method="post">
<div id="people-container">
<h3>Year 1:</h3>
<p>
<input name="people[1][first_name]">
</p>
</div>
Add! new year
<p>
<input type="submit" value="Save">
</p>
</form>
There are 5 boxes, which can be changed from 'white'<->'yellow' colors by mouse events (mouseover, mouseout and click). There is also a blue area with text displaying the level of the clicked box.
After clicking into the third box, I got 'hard level' text in blue area and 3 boxes color in yellow.
What I need is to return it to the default level ('easy level' and first box in yellow only) by clicking the reset button.
I have been trying do this like this , but it isn't working:
resetBtn = document.querySelector('#update');
and eventlistener:
resetBtn.addEventListener('click', highlightStars(`#star1`), true)
Here is an example:
window.addEventListener('DOMContentLoaded', changeStars, false);
const resetBtn = document.querySelector('#update');
/* Change level of the game depending on user choice */
function changeStars() {
/* Displaying level text inside blue box */
const updateAltText = currentLevelIndex => {
let levelText = document.querySelector('#level-text');
/* 'currentLevelIndex + 1' replaces event 'currentElement' */
levelText.textContent = document.querySelector(`#star${currentLevelIndex + 1}`).alt;
}
/* Captcha level number - default is 1 */
const getNumber = str => Number(str.match(/\d+/)[0]) || 1;
/* Star index is always one number lower than level number (indexing rules) */
const getStarIndex = event => getNumber(event.target.id) - 1;
let stars = document.querySelectorAll('.star');
const handleStarClick = event => {
/* FIRST - blocking possibility to change star behaviour by mouse events */
gameLevel.removeEventListener('mouseover', highlightStars);
gameLevel.removeEventListener('mouseout', highlightStars);
/* SECOND - making all needed star with yellow color */
const stars = document.querySelectorAll('.star');
for (let i = 0; i <= getStarIndex(event); i++) {
stars[i].classList.add('yellow');
}
};
const highlightStars = event => {
const starIndex = getStarIndex(event);
updateAltText(starIndex);
for (let i = 1; i <= starIndex; i++) {
const star = document.querySelector(`#star${i + 1}`);
star.classList.toggle('yellow');
}
};
// resetBtn.addEventListener('click', highlightStars(`#star1`), true);
resetBtn.addEventListener('click', updateAltText(0), true);
const gameLevel = document.querySelector('.game-level');
gameLevel.addEventListener("mouseover", highlightStars);
gameLevel.addEventListener("mouseout", highlightStars);
gameLevel.addEventListener('click', handleStarClick, {once: true});
}
.stars {
display: flex;
margin: 10px auto;
width: 500px;
}
input[type='image'] {
width: 60px;
height: 60px;
border: thin solid black;
}
.yellow {
background-color: yellow;
}
.game-level {
display: flex;
width: 300px;
height: 100%;
}
.level-block {
display: flex;
width: 200px;
margin-left: 10px;
justify-content: center;
align-items: center;
border: 1px solid hsl(217, 86%, 50%);
border-radius: 25px;
background-color: hsl(212, 29%, 80%);
}
.level-block > span {
font-size: 18px;
}
.reset {
width: 80px;
height: 80px;
}
<div class="stars">
<div class="game-level">
<input type="image" class="star yellow" id="star1" src="" width="60" alt="easy level">
<input type="image" class="star" id="star2" src="" width="60" alt="normal level">
<input type="image" class="star" id="star3" src="" width="60" alt="hard level">
<input type="image" class="star" id="star4" src="" width="60" alt="very hard level">
<input type="image" class="star" id="star5" src="" width="60" alt="impossible level">
</div>
<div class="level-block">
<span id="level-text">Easy level</span>
</div>
</div>
<input type="button" class="reset" id="update" value="RESET">
The following demo uses JavaScript for click events only, all mouse events (ie hover) are pure CSS. The reset behavior simply removes .active class on all buttons then adds .active class to the first button. Instead of the first button title being displayed after a reset -- the reset button title: "Game Reset" is displayed, it might be a little confusing for users if there's no confirmation of a reset. Other behavior is included in demo that is logical and consistent such as toggling, hovering to a temporary state and clicking for a persistent state etc. Details are commented in demo.
// Reference the form
const stars = document.forms.stars;
/*
Register the form to the click event -- when a click occurs anywhere on or within the form, callback function twinkle() is
called
*/
stars.onclick = twinkle;
/**
//A -- twinkle passes a reference to the Event Object... (e)
//B1 - Two Event Object properties are used to reference:
The tag the was clicked by user: event.target
The tag registered to the event: event.currentTarget
//B2 - The HTMLFormElement property: .elements collects all form
controls into a Live HTML Collection (aka NodeList)
//C -- ui.star is a Collection of form controls with [name=star]
The brackets [] and spread operator ... converts the
NodeList into an Array
//D -- Reference the message tag. If the clicked tag was the reset
button -- for...of loop iterates through each [name=star]
and removes the class .active from all [name=star]
//E1 - Next add .active class to the default button
//E2 - Set the legend.message text to the value of clicked button
[title] attribute...
~~~~~~~
//F -- ...But if a button.star was clicked, a check to verify if
clicked tag has the .active class -- then a for...of
loop identical to the one described in line D is used to
remove any .active class.
//G -- After there are no .active, the Boolean declared in line F
determines whether the clicked tag gets the .active class
and its [title] attribute displayed or not
*/
function twinkle(e) {
const active = e.target;
const ui = e.currentTarget.elements;
const starZ = [...ui.star];
const msg = document.querySelector(".message");
if (active.matches("#clear")) {
for (let star of starZ) {
star.classList.remove("active");
}
ui.star1.classList.add('active');
msg.textContent = active.title;
} else if (active.matches(".star")) {
let status = active.classList.contains("active");
for (let star of starZ) {
star.classList.remove("active");
}
if (!status) {
active.classList.add("active");
msg.textContent = active.title;
} else {
active.classList.remove("active");
msg.textContent = "";
}
}
return false;
}
:root {
font: 400 small-caps 2.5vw/1 Arial
}
.levels {
display: table;
width: 96%;
height: auto;
border: 1px solid hsl(217, 86%, 50%);
border-radius:4px;
}
.message {
display: table-caption;
width: 40vw;
height: 6vh;
margin: 0 auto 2vh;
padding: 0.5vh 0;
border: 1px solid hsl(217, 86%, 50%);
border-radius: 1.5rem;
background-color: hsla(212, 29%, 80%, 25%);
text-align: center;
font-size: 1.5rem;
color: #0078D7;
}
#clear {
float: right;
transform: rotate(45deg);
padding: 0;
border: none;
background: none;
font-size: 3.5rem;
cursor: pointer;
}
#clear:focus {
outline: 0;
}
/*
Flex is applied to the button.star'S parent tag so the order
property can be utilized.
*/
.flex {
display: flex;
justify-content: space-evenly;
align-items: center;
width: 70vw;
}
.star {
display: table-cell;
position: relative;
width: 16vw;
height: 24vh;
border: thin solid black;
background: #DDD;
font-size: 3.75rem;
text-align: center;
vertical-align: middle;
cursor: pointer;
}
/*
GSC (General Sibling Combinator: ~ ) provides highlighting across
multiple buttons.
Exp. 5 buttons: [-] [-] [X] ~ [>] ~ [>]
*/
.star.active,
.star:hover,
.star.active ~ .star,
.star:hover ~ .star {
background: gold;
}
/*
HTML layout has button.star in reverse order. Applying order to
each button rectifies the order by APPEARING in order while the
HTML structure remains reversed.
*/
#star1 {
order: 1;
border-top-left-radius: 6px;
border-bottom-left-radius: 6px;
}
#star2 {
order: 2;
}
#star3 {
order: 3;
}
#star4 {
order: 4;
}
#star5 {
order: 5;
border-top-right-radius: 6px;
border-bottom-right-radius: 6px;
}
#star1:hover,
#star1.active {
color: #5BC0DE;
}
#star2:hover,
#star2.active {
color: #FF1C8D;
}
#star3:hover,
#star3.active {
color: #00D800;
}
#star4:hover,
#star4.active {
color: #0000D5;
}
#star5:hover,
#star5.active {
color: #D50000;
}
<form id="stars" action="">
<fieldset name="levels" class="levels">
<legend class="message">Novice</legend>
<button id="clear" type="reset" title="Game Reset">π</button>
<section class="flex">
<button id="star5" name='star' class="star" title="Master">π</button>
<button id="star4" name='star' class="star" title="Expert">π</button>
<button id="star3" name='star' class="star" title="Advanced">π</button>
<button id="star2" name='star' class="star" title="Intermediate">π</button>
<button id="star1" name='star' class="star active" title="Novice">π</button>
</section>
</fieldset>
</form>
I'm creating a to-do list app, and in the app there is a div that wraps an input box (for the to-do item and so the user can edit the to-do) and a icon from font-awesome. When the user clicks on the icon, I want the entire div (which contains the to-do and the delete icon) to be deleted. But when tried to do that, it didn't work. Can someone help me?
Here's the JS Code
$(document).ready(() => {
$(".input input").on("keypress", check_todo);
$(".fa-trash").on("click", ".todo_container", delete_todo);
})
// delete todo
let delete_todo = (e) => {
e.target.remove();
}
// add todo
let add_todo = () => {
let todo = $(".input input").val();
$(".output").append(`
<input type="text" placeholder="Edit To-do" value="${todo}"><i class="fa fa-trash fa-lg" aria-hidden="true"></i>
`);
$(".input input").val("");
}
// check todo
let check_todo = (e) => {
if (e.keyCode == 13) {
if ($(".input input").val() == "") {
no_todo();
} else {
add_todo();
}
}
}
// no todo
let no_todo = () => {
alert("Please add a new todo");
}
See the html and a demo
You should binding to .out-put container.
$(".output").on("click",".fa-trash" , delete_todo);
http://codepen.io/Vrety/pen/WoWmaE
http://codepen.io/anon/pen/eBoXZe
In your event listener, you need to swap ".todo_container" and ".fa-trash".
$(".todo_container").on("click",".fa-trash" , delete_todo);
This statement means, when a click event occurs and bubbles up to .todo_container, check if the clicked element is .fa-trash, if so call the function.
Then change your delete function
let delete_todo = (e) => {
$(e.currentTarget).closest('.todo_container').remove()
}
This code means from the clicked icon, travel up the dom to find .todo_container, then remove it.
Good job with using the delegation in JQuery but while using it
$(".todo_container").on("click",".fa-trash" , delete_todo);
The base element $(".todo_container") needs to be static, You are deleting this also in the delete_todo() function.
Try using $(".output") instead and see if it works.
here is a working code
$(document).ready(function() {
$(".input input").on("keypress", check_todo);
//$(".fa-trash").on("click", ".todo_container", delete_todo);
$(".todo_container .fa-trash").on("click", delete_todo);
})
// delete todo
let delete_todo = function(e) {
//e.target.remove();
$(e.target).parent().remove();
}
// add todo
let add_todo = function() {
let todo = $(".input input").val();
//to do container element, the delete icon will added later
var toDoContainer = $(`
<div class="todo_container">
<input type="text" placeholder="Edit To-do" value="${todo}"></div>
`);
//create delete icon and set event listener
var elem = $('<i class="fa fa-trash fa-lg" aria-hidden="true"></i>').on("click", delete_todo).appendTo(toDoContainer);
$(".output").append(toDoContainer);
$(".input input").val("");
}
// check todo
let check_todo = (e) => {
if (e.keyCode == 13) {
if ($(".input input").val() == "") {
no_todo();
} else {
add_todo();
}
}
}
// no todo
let no_todo = () => {
alert("Please add a new todo");
}
#font-face {
font-family: Open Sans;
src: url("assets/fonts/OpenSans-Regular");
font-weight: 400
}
#font-face {
font-family: Open Sans;
src: url("assets/fonts/OpenSans-Semibold");
font-weight: 600
}
* {
margin: 0;
padding: 0;
transition: all 200ms ease-in-out;
}
*::selection {
background-color: #ffffaa;
}
.container {
width: 60%;
margin: 20px auto;
}
.header {
padding: 10px;
}
.header input {
padding: 10px;
width: 60%;
border: none;
outline: none;
font: 400 1.8em Open Sans;
}
.to-do {
padding: 10px;
text-align: center;
}
.input input {
padding: 10px;
width: 40%;
border: none;
outline: none;
font: 600 1em Open Sans;
border-bottom: 3px solid #333;
}
.output {
margin: 10px;
}
.output input {
padding: 20px;
border: none;
outline: none;
font: 600 1em Open Sans;
width: 50%;
cursor: pointer;
}
.output input:hover {
background-color: #eee;
}
.fa-trash {
padding: 20px;
cursor: pointer;
}
.fa-trash:hover {
background-color: #333;
color: #fff;
}
<head>
<title>To-do List</title>
<!-- FONTS -->
<link href="https://fonts.googleapis.com/css?family=Open+Sans:400,500" rel="stylesheet">
</head>
<body>
<div class="container">
<header class="header">
<input type="text" name="edit_name" placeholder="Edit Name">
</header>
<section class="to-do">
<div class="input">
<input type="text" name="add_todo" placeholder="Click To Add A New To-do">
</div>
<div class="output">
<div class="todo_container">
<input type="text" placeholder="Edit To-do" value="Todo #1"><i class="fa fa-trash fa-lg" aria-hidden="true"></i>
</div>
<div class="todo_container">
<input type="text" placeholder="Edit To-do" value="Todo #2"><i class="fa fa-trash fa-lg" aria-hidden="true"></i>
</div>
</div>
</section>
</div>
<!-- JQUERY -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<script src="https://use.fontawesome.com/5840114410.js"></script>
</body>
I have a page with a link to a form. After clicking the link the form shows up and the link disappears. The problem that i have is, when i click the browser's back button, the values of the URL is changed, but the state of the page doesn't go back to previous state. The form should disappear and the link shows back. Also on reload when the form is visible, the page goes back to its first state, which i need to prevent from happening.
Code :
<html>
<style>
.titimmo {
text-align: center;
padding: 10px;
font-size: 14pt;
background-color: #CC3300;
display: block;
}
.hidden {
display: none;
}
.visible {
display: block;
}
#formContainer {
padding: 1em 0 1em 2em;
background-color: #E8E8E8;
margin: 1em 0 1em 2em;
width: 88.9%;
}
#formContainer h4 {
color: #FF3300;
}
</style>
<body>
<div id="categContainer1">
<div class="titimmo">Real Estate</div>
</div>
<div id="formContainer" class="hidden">
<form action="add.php" method="post">
<h4>Location :</h4>
<input type="text" name="made"/>
<h4>Price :</h4>
<input type="text" name="modele"/><br/><br/>
</form>
</div>
<script>
function stepone() {
document.getElementById('a_categ').onclick = function () {
document.getElementById('categContainer1').className += " hidden";
document.getElementById('formContainer').className = "visible";
window.history.pushState('Form', 'My form', this.getAttribute("href"));
return false
};
}
stepone();
</script>
</body>
</html>
First question is: How to bring back the page to its previous state by clicking the browser's back button?
Second question is: How to prevent the page from going back to its previous state - on reload when it's on second state (when form is visible)?
There are two things you need to do to make it work:
To monitor browser back button click, use
window.onpopstate
method
To remember the form state, you need to store the value in
localStorage or in a cookie.
This is a basic example:
var formVisible = localStorage.formVisible || false;
var cContainer = document.getElementById('categContainer1');
var fContainer = document.getElementById('formContainer');
function formOpen(e) {
cContainer.className = "hidden";
fContainer.className = "visible";
window.history.pushState('Form', 'My form', this.getAttribute("href"));
localStorage.formVisible = 'Y';
return false;
};
function formClose(e) {
cContainer.className = "visible";
fContainer.className = "hidden";
localStorage.removeItem( 'formVisible' );
};
if( formVisible ) formOpen();
document.getElementById('a_categ').onclick = formOpen;
window.onpopstate = formClose;
var formVisible = localStorage.formVisible || false;
var cContainer = document.getElementById('categContainer1');
var fContainer = document.getElementById('formContainer');
function formOpen(e) {
cContainer.className = "hidden";
fContainer.className = "visible";
window.history.pushState('Form', 'My form', this.getAttribute("href"));
localStorage.formVisible = 'Y';
return false;
};
function formClose(e) {
cContainer.className = "visible";
fContainer.className = "hidden";
localStorage.removeItem( 'formVisible' );
};
if( formVisible ) formOpen();
document.getElementById('a_categ').onclick = formOpen;
window.onpopstate = formClose;
.titimmo {
text-align: center;
padding: 10px;
font-size: 14pt;
background-color: #CC3300;
display: block;
}
.hidden {
display: none;
}
.visible {
display: block;
}
#formContainer {
padding: 1em 0 1em 2em;
background-color: #E8E8E8;
margin: 1em 0 1em 2em;
width: 88.9%;
}
#formContainer h4 {
color: #FF3300;
}
<div id="categContainer1">
<div class="titimmo">
Real Estate
</div>
</div>
<div id="formContainer" class="hidden">
<form action="add.php" method="post">
<h4>Location :</h4>
<input type="text" name="made" />
<h4>Price :</h4>
<input type="text" name="modele" />
</form>
</div>
Also on Fiddle, where you can actually see how it works.