page back button not resetting css - javascript

I have a button that "navigates" to a new page.
To do this the button makes the current section's/page's display settings = none and the new section/page's display = block.
<div class="listLeft"><p class="listItems" onclick="navButtons('work')">work</p><p class="listItems" onclick="navButtons('about')">about</p></div>
<div class="listRight"><p class="listItems" onclick="navButtons('playground')">playground</p><p class="listItems" onclick="navButtons('contact')">contact</p></div>
js below
function navButtons(page) {
let section = document.getElementById(page);
section.setAttribute("class", "visible");
window.location.href = `#${page}page`;
window.scrollTo(0, document.body.scrollHeight);
let pagesArrayCopy = [...pagesArray]
const unselected = pagesArrayCopy.filter(item => item.id !== page);
setTimeout(() => {
unselected.forEach((el, index) => unselected[index].setAttribute("class", "invisible"));
pagesArray = Array.from(pagesNodeList);
}, 500);
};
when I press the back button the url is obviously changing back to the old #section, but the css doesn't reset, so the new page is still visible and the previous page is still display = none.
How do i get around this, so when the back button is pressed the css values reset to default?

Try to use an anchor tag so your URL actually change (ie: update the adress to mypage.html#page2).
Then you could bind a function to onhashchange and check of your page is well displayed.

you haven't supplied all the html. there's no id work so section is null
function navButtons(page) {
let section = document.getElementById(page);
console.log(section)
section.setAttribute("class", "visible");
window.location.href = `#${page}page`;
window.scrollTo(0, document.body.scrollHeight);
let pagesArrayCopy = [...pagesArray]
const unselected = pagesArrayCopy.filter(item => item.id !== page);
setTimeout(() => {
unselected.forEach((el, index) => unselected[index].setAttribute("class", "invisible"));
pagesArray = Array.from(pagesNodeList);
}, 500);
};
<div class="listLeft">
<p class="listItems" onclick="navButtons('work')">work</p>
<p class="listItems" onclick="navButtons('about')">about</p></div>
<div class="listRight">
<p class="listItems" onclick="navButtons('playground')">playground</p>
<p class="listItems" onclick="navButtons('contact')">contact</p></div>

Another way to do this is to bind your changing state to the history of the browser. Since there is no real way of overriding the 'back' button on the browser, you will have to write it into your history. See the History API for HTML5 here:
https://css-tricks.com/using-the-html5-history-api/
The same thing specified above can also be done with this plugin:
https://code.google.com/archive/p/reallysimplehistory/

Related

React/animation - render animation everytime on button click when state or props change

I am trying to have the animation work everytime i click on the buttons in the below project
Code - https://codesandbox.io/s/8fjs8i
Description
There are 3 buttons named first, second and third. when i click on first, the purple box below shows first, when i click on second it shows second and so on, basically the div is updating everytime based on button click.
Problem : but the animation fadIn that i have given to the div works only on application load. how can i make it work everytime i click the button so the the box fadesIN with animation for every click.
const Renders = ({ arr }) => {
const [load, setLoad] = useState(false);
useEffect(() => {
setLoad(true);
setTimeout(() => {
setLoad(false);
}, 1);
}, [arr]);
if (load) return <></>;
return (
<div className="renders">
<div className="zoomers">{arr}</div>
</div>
);
};
This another way you can do it:
const Renders = ({ arr }) => {
const [load, setLoad] = useState(false);
useEffect(() => {
setLoad(true);
setTimeout(() => {
setLoad(false);
}, 1);
}, [arr]);
return (
<div className="renders">
<div className={load ? '' : "zoomers"}>{arr}</div>
</div>
);
};
Now look the different, before you load and unload, now its just a play with the class name, the idea that every time you load element with the animation class so its start to work

I Want a Button that hide the div and restore it

I want to create a button that will hide each ticket and one general button that will restore them all.
this is the Code:
return (
<ul className="tickets">
{filteredTickets.map((ticket) => (
<li key={ticket.id} className="ticket">
<h5 className="headline">{ticket.headline}</h5>
<p className="text">{ticket.text}</p>
<footer>
<div className="data">
By {ticket.address} | {new Date(ticket.time).toLocaleString()}
</div>
</footer>
</li>
))}
</ul>
);
here is an example of what you want!
you have to replace myFunction() for your button and myDIV into your element that you want to hide it!
<button onclick="myFunction()">Click Me</button>
function myFunction() {
var x = document.getElementById("myDIV");
if (x.style.display === "none") {
x.style.display = "block";
} else {
x.style.display = "none";
}
}
for react =
const [visible, setVisible] = useState(true)
here is for button
<button onlick={() =>setVisible(!visible)}>hide/show
here is a demo in JS, modify to what you want exactly
<ul class="ticket">
<li>
<p>hey, I'm a P</p>
<div class="data">I'm a Div</div>
</li>
</ul>
.hide {display:none}
const generalBtn = document.getElementById(`btn`);
const divContainer = document.querySelector(`.ticket`);
const eachDiv = divContainer.getElementsByClassName(`data`);
generalBtn.addEventListener(`click`, () => {
[...eachDiv].forEach((div) => {
div.classList.toggle(`hide`);
});
});
There is a good solution in your case but as mentioned in the comments, it needs to manipulate the filteredTickets array.
You need to add a property/value to each item of filteredTickets to track or change their state. For example, it can be isVisible property which is a boolean with false or true value.
Now, isVisible value will determine the behavior. let's modify the ticket:
const handleHideTicket = (id) => {
// find selected ticket and ​change its visibility
​const updatedFilterdTickets = filteredTikcets.map(ticket => (ticket.id === id ? {...ticket, isVisible: false} : ticket))
// now the updatedFilterdTickets need to be set in your state or general state like redux or you need to send it to the server throw a API calling.
}
return (
​<ul className="tickets">
​{filteredTickets.filter(ticket => ticket.isVisible).map((ticket) => (
​<li key={ticket.id} className="ticket">
​<h5 className="headline">{ticket.headline}</h5>
​<p className="text">{ticket.text}</p>
​<footer>
​<div className="data">
​By {ticket.address} | {new Date(ticket.time).toLocaleString()}
​</div>
// add a button to control visibility of each ticket
​<button onClick={() => handleHideTicket (ticket.id)}> click to hid / show </button>
​</footer>
​</li>
​))}
​</ul>
);
Explanation:
a new button added to each ticket and pass the handleHideTicket handler to it. If the user clicks on this button, the handler finds that ticket and sets the isVisible property to the false.
On the other hand, we can remove the hidden tickets by applying a simple filter method before map method. so only visible tickets will be displayed.
Now, create a general button to show all the tickets. In this case, you need a handler function that sets all ticket's isVisible value to true
const handleShowAllTickets = () => {
const updatedFilteredTickets = filteredTickets.map(ticket => ({...ticket, isVisible: true}))
// now put the updatedFilteredTickets in your general store/post an API call/ update state
}
Note: as I mentioned in the code's comments, you need to update your filteredTickets array after changing via handlers to reflect the changes in your elements.

My React function gets called twice, with the second call setting values incorrectly

i have a function that calculates pages and page buttons based on an api. Inside the buttons get rendered and they have an onClick function. When i click the button, this is supposed to happen:
sets the current page number and writes it into state
calls the api which gets text elements to display according to current page
evaluates page buttons and numbers based on api and marks the current page with a css class
event handler:
handleClick(event) {
let currentPage = Number(event.target.id)
localStorage.setItem("currentPage", currentPage)
this.setState ({
currentPage: currentPage
})
this.fetchApi()
}
then i'm returning the component that deals with pages:
return(
<div>
<Paging
data = {this}
currentPage = {this.state.currentPage}
state = {this.state}
lastPage = {this.state.lastPage}
handleClick = {this.handleClick}
/>
</div>
)
and the component looks like this:
function Paging(props) {
const apiPaging = props.state.apiPaging
const apiPagingSliced = apiPaging.slice(1, -1)
const renderPageNumbers = apiPagingSliced.map((links, index) => {
return <button key={index} id={links.label}
onClick={(index)=>props.handleClick(index)}
className={(links.active ? "mark-page" : "")}
>{links.label} {console.log(links.label) }
</button>
})
return (
<div id = "page-nums">
{renderPageNumbers}
</div>
)
So what happens is that Paging() function gets called twice. There is a handy value inside the api called "active" (links.active) which is a boolean, and if set to true, means that the page is the current page. i then add a class "mark-page" on to highlight that i'm currently on that page. If i {console.log(links.label)} i see that it's invoked twice, first being the correct values and second being the previously clicked values. So it works correctly only if i reload the page again.
i.e if i click page 2,it stays on page 1 and marks page 1. if i then click page 3, it marks page 2. and (afaik) Paging() gets only invoked once, at the end of my only class (Body).
I've been at it yesterday and today and have no idea anymore.
change your handleClick function to this.
handleClick(event) {
window.scrollTo({
top: 0,
behavior: 'smooth',
});
if (event.target.id >= 1) {
let currentPage = Number(event.target.id);
localStorage.setItem('currentPage', currentPage);
this.setState({
currentPage: JSON.parse(localStorage.getItem('currentPage')),
},()=>{
this.fetchApi();
});
}
}
in your fetchApi function you reference currentPage as below.
const apiQuery = JSON.parse(this.state.currentPage);
But it hasn't updated yet.
see https://reactjs.org/docs/react-component.html#setstate

Reset html link attribute

I have the following line in my html
a link
Then I'm using the chrome dev console to change the attribute data-url to another link. Can I in some way afterwards reset this link to its default value? I've seen a reset() function but I guess it doesn't work for this problem.
Store in another attribute
const anc = document.getElementById("anc1");
anc.dataset.saveurl = anc.dataset.url;
anc.dataset.url="otherurl";
Click
result:
Click
Another perfect use case for WeakMaps! 🎉🎉🎉
const wm = new WeakMap()
document.querySelectorAll('button').forEach(el => {
wm.set(el, el.dataset.url)
delete el.dataset.url
el.onclick = () => {
console.log('html:', el.outerHTML, '\nweakmap:', wm.get(el))
}
})
<button data-url="img/1.jpg">Click</button>
<br>
<button data-url="img/2.jpg">Click</button>
<br>
<button data-url="img/3.jpg">Click</button>

Scroll event not working in framework7 - Vue

Am currently using framework7 and I have this problem wherein I need to get a button floating once the user pass scrolling a specific element.
But for some reason am not able to make the scroll event work. Even used a native event listener but still no luck.
Here is my code. In my component:
export default {
methods: {
handleScroll(event) {
alert('should work')
}
},
created() {
window.addEventListener('scroll', this.handleScroll);
},
destroyed() {
window.removeEventListener('scroll', this.handleScroll);
},
mounted() {
window.addEventListener('scroll', this.handleScroll)
this.handleScroll;
var element = document.querySelector(".similar-adventures");
var top = element.offsetTop;
window.scrollTo(0, top);
}
}
And here is my native event listener code:
window.addEventListener(‘scroll’, function(e){
// Get the new Value
newValue = window.pageYOffset;
//Subtract the two and conclude
if(oldValue - newValue < 0){
console.log(“Up”);
} else if(oldValue - newValue > 0){
console.log(“Down”);
}
// Update the old value
oldValue = newValue;
});
I know this is old now but i will answer for future reference, so i think the problem here is that the window is not actually scrolling as framework7 uses pages/views.
In vue the renders to 2 divs like so..
<f7-page>
<div slot="fixed">Fixed element</div>
<p>Page content goes here</p>
</f7-page>
<!-- Renders to: -->
<div class="page">
<div>Fixed element</div>
<div class="page-content">
<p>Page content goes here</p>
</div>
</div>
i found that its the page-content class that you want to put the eventListenter on best way to do this is Dom7 like so...
let page = $$('.page-content')
page.on('scroll', () => {
console.log(page.scrollTop()) // will show page top position
page.scrollTop(0) // will scroll to top
})
//if you have multiple pages
let page = $$('.page-content')
let home = $$(page[0])
let about = $$(page[1])
page.on('scroll', () => {
console.log(home.scrollTop()) //home page top position
console.log(about.scrollTop()) //about page top position
})
//more options
page.scrollTop(position, duration, callback)
page.scrollTo(left, top, duration, callback)
just remember to import $$ from 'Dom7'
This code retrieves all the pages from the f7 component in an array
let pages = document.querySelectorAll('.page-content');
Then to make a page scrollable, select the respective index and do:
pages[0].addEventListener('scroll', function () { console.log('is scrolling...') } );
For the same code but in a more beautiful way as we don't want to specify the page by index:
add an id to your f7-page tag
<f7-page name="whatever" id='myPage'>
then do this code for example in mounted:
let f7page = document.getElementById('myPage');
let scrollableDiv = f7page.querySelector('.page-content');
scrollableDiv.addEventListener('scroll', function () { console.log('is scrolling...') } );
special thanks to BiscuitmanZ's comment for finding the underlying issue

Categories