I need to redirect the web page after it loads and gets the param from the URL. I can do this with a button click.
However, I want to redirect the page automatically (without user input so better UX). Here I use window.addEventListener('load', () => handleClick()) and it works well on Chrome, but it does not always fire on Safari (desktop and mobile).
I can debug this by adding alert('Beginning'); in the handler — on Chrome, this fires automatically after the page load, but not on Safari.
How I can solve this?
const handleClick = async (event) => {
alert('Beginning'); //For debugging
const stripe = await stripePromise;
const { error } = await stripe.redirectToCheckout({
param,
});
}
if (typeof window !== `undefined`) {
const param = new URLSearchParams(window.location.search).get('param');
}
const Page = () => {
if (typeof window !== `undefined`) {
window.addEventListener('load', () => handleClick())
}
return (
<section >
<button role="link" onClick={handleClick}> //Only for fallback
Press
</button>
</section>
);
};
export default Page;
Without clicking the button you can use history.push function.Since it fires as soon as it is called.
history.push(location)
Related
I am developing my web developer portfolio. In that when I press the hamburger, the color of the top nav bar should also change. But sometimes in Chrome it doesn't change and I have to reload. I thought it is probably because the script didn't load. But even after waiting for a long time this bug occurs. Can anyone say why it happens and how to solve it. Note that this color change is only for mobile nav. The source code is available at https://github.com/mrjithin/my-portfolio/ . And the script that does this thing is available with the name ham.js in the scripts folder.
The top color should have been the same as the color of the rest of the navbar.
// ham.js
// For mobile hamburger
const mobNav = document.querySelector("nav#mobile");
const deskNav = document.querySelector("nav.desktop");
const navColor = window.getComputedStyle(mobNav).getPropertyValue("background-color");
document.getElementsByClassName("ham")[0].addEventListener("click", (event) => {
document.getElementsByClassName("ham")[0].classList.toggle("cross");
document.getElementById("line2").classList.toggle("none");
mobNav.classList.toggle("on");
mobNav.classList.toggle("off");
if(mobNav.className === "on"){
deskNav.style.backgroundColor = navColor;
} else {
deskNav.style.backgroundColor = "";
}
event.stopPropagation();
});
// To close the navbar on clicking a link.
const mobileLis = document.querySelectorAll("nav#mobile a");
Array.from(mobileLis).forEach(link => {
link.addEventListener("click", event => {
document.getElementsByClassName("ham")[0].classList.toggle("cross");
document.getElementById("line2").classList.toggle("none");
mobNav.classList.toggle("on");
mobNav.classList.toggle("off");
if(mobNav.className === "on"){
deskNav.style.backgroundColor = navColor;
} else {
deskNav.style.backgroundColor = "";
}
event.stopPropagation();
})
})
Thanks in advance!
Instead of this code
const navColor = window.getComputedStyle(mobNav).getPropertyValue("background-color");
try this one
const navColor = () => window.getComputedStyle(mobNav).getPropertyValue("background-color");
And call navColor as a function navColor()
I can disable opening new tab or window in case of <a> tag by removing target attribute e.g. target='_blank'
In some cases instead of <a> website put <button> and add onClick() or submit() etc which programmatically generates a link and sets the target attribute.
<button id="653cde4c-1620-11ec-85b5-5ae26c154b46">
<div>click here</div>
</button>
In some webpack generated javascript file there would be something like which would not be easy to find and read minified code.
var button = document.querySelctor('653cde4c-1620-11ec-85b5-5ae26c154b46')
// Add whatever you want to add to this button element, e.g. add onClick() or submit() or something else which I am not sure of
We can see image at https://i.stack.imgur.com/8oG5w.png
In such case where <button> is providing link click functionality. I can not view and edit onClick() or submit() etc as its webpack generated javascript. I can only run my javascript code after loading of that webapge in devtools console.
How can I disable opening new tab or new window of browser in such case? Or What javascript code should I run to override <button> link behaviour?
Depending on how the webpack based code does manage the tab handling of resources one possible solution was to wrap own code around window.open or even entirely replace it with an own implementation.
As for the wrapping, based on the intercepted data, one could decide of whether one does suppress the url-handling entirely or, instead of opening a new tab/window, does a forwarding to location.href or even proceed with invoking the original window.open.
// untouchable 3rd party code
//
function alienLocationHandler({ currentTarget }) {
let { url, target } = currentTarget.dataset;
url = (url ?? '').trim();
if (url) {
target = (target ?? '').trim();
if (target) {
// due to SO's permission handling ...
//
// ... Blocked opening 'https://stackoverflow.com/' in a
// new window because the request was made in a sandboxed
// frame whose 'allow-popups' permission is not set.
//
window.open(url, target);
} else {
window.location.href = url;
}
}
}
document
.querySelectorAll('[data-url]')
.forEach(elmNode =>
elmNode.addEventListener('click', alienLocationHandler)
);
// one possible approach :: wrap around `window.open`
//
window.open = (function createAroundHandler(proceed, thisArg) {
return function aroundWindowOpen(url, target, ...rest) {
console.log('aroundWindowOpen ...', {
url,
target,
rest,
});
// - of cause all the code is just for demonstration purpose.
//
// - the OP has to come up with own handler logic which does
// fit the OP's needs best.
if (url !== 'https://stackoverflow.com') {
// invocation of the original `window.open`
// will be blocked by SO's permission handling.
proceed.call(thisArg, url, target, ...rest);
} else {
// delayed fowarding to `location.href`.
setTimeout(() => { window.location.href = url }, 5000);
}
};
}(window.open, window));
body { margin: 0; }
.as-console-wrapper { min-height: 87%; top: auto; }
<button data-url="https://stackoverflow.com">
no interception
</button>
<button
data-url="https://google.com"
data-target='google'
>
intercepted & open attempt
</button>
<button
id="_653cde4c-1620-11ec-85b5-5ae26c154b46"
data-url="https://stackoverflow.com"
data-target='_blank'
>
intercepted and forwarded with 5sec delay
</button>
Another approach was to make use of event delegation by listening to and handling click events at e.g. document.body level.
// untouchable 3rd party code
//
function alienLocationHandler({ currentTarget }) {
let { url, target } = currentTarget.dataset;
url = (url ?? '').trim();
if (url) {
target = (target ?? '').trim();
if (target) {
// due to SO's permission handling ...
//
// ... Blocked opening 'https://stackoverflow.com/' in a
// new window because the request was made in a sandboxed
// frame whose 'allow-popups' permission is not set.
//
window.open(url, target);
} else {
window.location.href = url;
}
}
}
document
.querySelectorAll('[data-url]')
.forEach(elmNode =>
elmNode.addEventListener('click', alienLocationHandler)
);
// another possible approach :: event delegation
//
// - [https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events#event_delegation]
// - [https://davidwalsh.name/event-delegate]
//
// - [https://javascript.info/event-delegation]
// - [https://learn.jquery.com/events/event-delegation/]
//
function isButtonEvent(activeElement, targetNode) {
return (activeElement.tagName.toLowerCase() === 'button') && (
activeElement.isSameNode(targetNode) ||
activeElement.contains(targetNode)
);
}
function preventSpecificButtonClickBehavior(evt) {
const elmButton = document.activeElement;
if (isButtonEvent(elmButton, evt.target)) {
const url = (elmButton.dataset.url ?? '').trim();
const isUrlBasedPrevented = (url !== 'https://stackoverflow.com');
const isIdBasedPrevented = ((elmButton.id ?? '').trim() !== '');
if (isUrlBasedPrevented || isIdBasedPrevented) {
evt.stopImmediatePropagation();
evt.stopPropagation();
if (isUrlBasedPrevented) {
console.log('prevented button click behavior ... URL based')
}
if (isIdBasedPrevented) {
console.log('prevented button click behavior ... ID based')
}
}
}
}
document
.body
.addEventListener(
'click',
preventSpecificButtonClickBehavior,
// - [https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#parameters]
// - The boolean `useCapture` parameter/flag does the trick if set as `true` value.
true
);
body { margin: 0; }
.as-console-wrapper { min-height: 87%; top: auto; }
<button data-url="https://stackoverflow.com">
click behavior not prevented
</button>
<button
id="_653cde4c-1620-11ec-85b5-5ae26c154b46"
data-url="https://stackoverflow.com"
>
prevented behavior (id based)
</button>
<button
data-url="https://google.com"
data-target='google'
>
<span>
<span>
prevented behavior (url based)
</span>
</span>
</button>
Probably the logic in the onClick() does something like window.open(url, [params]). You can change this to setting window.location.href = url; and the url will be loaded in the same window.
I try to console some message when image is fully loaded using 'load' listener, but the code did not work, how to properly write a 'load' event listener in react ? Thankyou
useEffect(() => {
window.addEventListener('load', (event) => {
const imageTest = document.querySelector('img')
const isLoaded = imageTest.complete && imageTest.naturalHeight !== 0
console.log(isLoaded)
})
}, [])
This is not how react works. You are trying to use load event within the component when everything else is already loaded within from <div id="root"></div>.
React is Single Page App. And for the whole document load happens once only :)
However for individual elements we can set onload and fire that event in componentDidMount() or in useEffect() Hook
UPDATE: For image load check you do something like. You can do this or even use useRef()
useEffect(() => {
const imageTest = document.querySelector('img');
imageTest.onload = ()=>{
// Image is loaded and your further steps :)
const isLoaded = imageTest.complete && imageTest.naturalHeight !== 0
console.log(isLoaded);
}
}, []);
There is also one more easy way to do this:
Using onLoad synthetic event right on the image element itself. Which I think should also work fine:
const ImageLoadDemo ()=> {
const handleImageLoaded =()=> {
console.log("Image was successfully loaded");
}
const handleImageErrored =()=> {
console.log("Image was not loaded successfully");
}
return (
<div>
<img
src="https://picsum.photos/200/300"
onLoad={handleImageLoaded}
onError={handleImageErrored}
/>
</div>
);
}
The way to listen image is successfully loaded in react component is just put onLoad on your <img> tag, for example :
const MyCompoent = () => {
return <img src="yourImageLink.png" onLoad={()=>{console.log('The Image is successfully loaded')} } />
}
instead console a message you can pass a function as well
I want to know how to make a Tab highlight everytime an event happens, in this case, it would be a call. So, if the user isn't in my website in the moment, he will know that a event happenned. My useEffect looks like the following:
useEffect(() => {
if (newCall < calls.length){
setHighlight(true)
setNewCall(calls.length)
}
}, [calls.length])
useEffect(() => {
if (newCall < calls.length){
setHighlight(!'your state name')
setInterval(()=>setHighlight(!'your state name'),2000)
setNewCall(calls.length)
}
}, [calls.length])
The above fragment of code sets highlight and so does the user knows that an event has happened and after 2 seconds the highlight will be returned to the initial state.
It seems as though the solution is a combination of:
Browser tab change notification like when you get a new gmail e-mail or a new tweet in Twitter
and
Detect If Browser Tab Has Focus
useEffect(() => {
window.onfocus = function(){
document.title = "Original Title"
}
return () => {
window.onfocus = null;
}
}, []);
useEffect(() => {
if (newCall < calls.length){
document.title = `Original Title (${calls.length} calls)`
}
}, [calls.length])
browser back or fore can't call 'onChange' API, so that the page list can't update according to current page
onPageChange = (page, pageSize) => {
const { dispatch } = this.props
const param = {
blogId: this.props.params.id,
pageIdx: page,
quantity: pageSize
}
dispatch(fetchIssues('getComments', param, ''))
hashHistory.push({
pathname: `/post/${this.props.params.id}`,
query: { pageIdx: page }
})
}
render() {
return <Pagination onChange={onPageChange} total={50} />
}
First, you need to take into account the browser back or fore click event. that event call popstate The popstate event is fired each time when the current history entry changes (user navigates to a new state). That happens when user clicks on browser's Back/Forward buttons or when history.back(), history.forward(), history.go() methods are programatically called.
in Javascript
window.addEventListener('popstate', function(event) var r = confirm("You pressed a Back button! Are you sure?!");
window.addEventListener('popstate', function(event) {
// The popstate event is fired each time when the current history entry changes.
if (r == true) {
// Call Back button programmatically as per user confirmation.
history.back();
// Uncomment below line to redirect to the previous page instead.
// window.location = document.referrer // Note: IE11 is not supporting this.
} else {
// Stay on the current page.
history.pushState(null, null, window.location.pathname);
}
history.pushState(null, null, window.location.pathname);
}, false);