I am currently working on showing success/fail message on the redirected page.
The workflow will look like this,
User type something in pageA and submit. then do history.push to next page.
history.push(/pageB/path, {message: 'Success!'});
and in pageB, it will show success message on the top.
However, this success message will be there forever, then this will confuse user if they follow the previous steps and go to pageA again. And then go back to pageB(could be back button on browser or cancel button on the form) without submit. This message will still be shown on top of the page.
My goal is to only show message after user submit the form. So my question is is there a way to make the history state volatile so the message won't show up when user just went back to pageB.
Any suggestion is welcome. Thanks!
Edit: My currently solution is checking history's action(pop or push) and only show message when action is push. But looking for any better solution.
Edit: To more clarify my problem. Here is user action and browser history.
Action: user in pageA and submit form.
History:
0: pageA
Action: user has been redirected to pageB(with success message)
History:
0: pageA
1: pageB with history.location.state.message = ...
Action: user go to pageA again without submit a form
History:
0: pageA
1: pageB with history.location.state.message = ...
2: pageA
Action: user go back to pageB by back button of browser
History:
0: pageA
1: pageB with history.location.state.message = ...
In the step 4, it goes back to old history 1 which has message set in state so it will still present(but should not, because user didn't submit a form).
Edit: I am thinking if it is possible to directly modify history to remove the state from the page?
with the following code you can pass the prop after a form is submitted
history.push({pathname:'/pageB', message: 'successs'})
and then in pageB
this.setState({ isMessageTextTimeExpired: false }) // in constructor
componentDidMount() {
if (this.state.isMessageTextTimeExpired) {
setTimeout( () => {
this.setState({ isMessageTextTimeExpired: true });
}, 5000) // your desire time to hide message
}
}
componentWillReceiveProps(nextProps) {
const previousPath = this.props.location.pathname;
if (previousPath === 'pathA') {
this.setState({ isMessageTextTimeExpired: true })
}
}
render() {
const { redirectMessage } = this.props.history.location;
const { isMessageTextTimeExpired } = this.state;
return (
redirectMessage && isMessageTextTimeExpired ? redirectMessage : null // print redirectMessage if it exist
)
}
With the above, whenever you reach pathB without passing it message it would simply not show anything. If message exist it will be rendered but removed after 5 seconds. Also, if your previous path was pathA it would not show the message
Related
I am getting an error when I try to click each of the pages one by one in the following way:
I have tried using the .click function of puppeteer but it gives me the error:
Error: Execution context was destroyed, most likely because of a navigation.
const aTags= await page.$$('#someId > a')
for (const aTag of aTags) {
await aTag.click();
//Do stuff
page.goto(url); //this goes back to the initial page with the list of URLs
}
Would like to click the links one by one and return to the previous page
well if you go to the new page by clicking on the first link , you cant click on the rest of them ... bcuz you're not in the links page anymore
just collect all the links into an array ... just use another function to open the links
for (const aTag of aTags) {
let href = await page.evaluate(el => el.getAttribute('href'), aTags);
await open_links(href);
}
async function open_links( url ){
// open new tab with the url
}
Hello,
I already checked the answers from the question PushPad: Subscribe is removed after site refresh, but it did not help me.
I created a subscribe/unsubscribe button, following the doc, and the prompt is showing up on Firefox each time i click on the subscribe button so i guess my flow is correct but i don't understand why it's not working on Chrome => the prompt is only showing the first time i launch Chrome.
Here is what i do
pushpad('init', #projectID);
var pushId = $("#main").data("pushid");
var pushSig = $("#main").data("pushsig");
var updateButton = function (isSubscribed) {
var btn = $('#activate-push-notif');
if (isSubscribed) {
btn.html('Unsubscribe');
btn.addClass('subscribed');
} else {
btn.html('Subscribe');
btn.removeClass('subscribed');
}
};
// check whether the user is subscribed to the push notifications and
// initialize the button status (e.g. display Subscribe or Unsubscribe)
pushpad('status', updateButton);
// when the user clicks the button...
$('#activate-push-notif').on('click', function (e) {
e.preventDefault();
// if he wants to unsubscribe
if ($(this).hasClass('subscribed')) {
pushpad('unsubscribe', function () {
updateButton(false);
}, {
uid: pushId,
});
// if he wants to subscribe
} else {
// try to subscribe the user to push notifications
pushpad('subscribe', function (isSubscribed) {
if (isSubscribed) {
updateButton(true);
} else {
updateButton(false);
alert('You have blocked notifications from your browser preferences.');
}
}, {
uid: pushId,
uidSignature: pushSig
});
}
});
Thanks for your help to figure it out.
Make sure that you wrap all your code inside $(function () { ... }, so that your code is run when the page is fully loaded, otherwise your click handler may not work properly.
Probably the point is that when you see the Firefox prompt you click "Not now" (instead of "Never allow" which is hidden under the ▼ menu). That is why you can see the prompt multiple times. In other browsers, like Chrome, the default option is "Block" (which is a permanent block, like "Never allow").
When the user blocks the notifications you cannot display the browser prompt again, due to browser restrictions... however there are some alternative solutions. For example you can display a custom prompt as many times as you want, and then display the browser prompt only if the user says yes to your custom prompt. See this example. Otherwise you can display a prompt only to users who have blocked the notifications, asking to unblock the notifications. See this example. Another option is to display a button in the page to allow the users to subscribe to notifications when they decide to do that.
window.addEventListener('popstate', function(event) {
alert("you are not able to push back button");
});
I have create the web application using polymer 2.0 but I have to click on the back button to the browser is logout I have to show the alert if the user is click on the back button of the browser I have tried window.addEventListener but still got error.
I've not been able to stop the browser's back button, but I've managed to get around it. In my app, I want to warn the user that they will log out by backing up to the first page, and give them a chance to leave or stay put. Using the polymer-2-starter-kit as my starting point, and tracking a connected property, I got this working:
_routePageChanged(page) {
// If no page was found in the route data, page will be an empty string.
// Default to 'home' in that case.
this.page = (page && this.connected) ? page : 'home';
// Close the drawer.
this.drawerOpened = false;
}
_pageChanged(page, oldPage) {
// Warn user if backing up logs out.
if ((page == '' || page == 'home') && this.connected) {
if (window.confirm("Do you really mean to logout?")) {
this.$.xhrLogout.generateRequest();
} else {
window.history.forward();
}
}
const resolvedPageUrl = this.resolveUrl('my-' + page + '.html');
Polymer.importHref(
resolvedPageUrl,
null,
this._showPage404.bind(this),
true);
}
So if the user is connected, and navigates to the initial page, I can force them to stay on the page where they were with window.history.forward().
I have a url at /page (PAGE A) where I want to detect if the page was navigated to with history back from (PAGE B) or if the user was on (PAGE A) and manually refreshed the page from the URL bar refresh button (without using history back).
I looked into all the history, location, props by react router but didn't find a way to differentiate how the user navigated to the page.
In both scenarios, the history.action == 'POP' is the history action. Ideally it would be 'POP' when using the back button in the app to go back from page b to page a, and when on page a, when refreshing the page, it would be something other than 'POP' like 'REFRESH' for example.
How can we differentiate between both of them to run different logic in our app, since both trigger 'POP'?
Instead of comparing the history key, you can compare the pathname, for example, if you are in the page "/page1/page2" and hit refresh, the new location is the same. But if you hit the back action, the new location will be "/page1/".
This solution also uses a listener to listen to any action coming from history.
componentDidMount() {
const unlisten = history.listen((location, action) => {
if (action == 'POP') {
\\ thisLocation is the current location of your page
if (location.pathname != '/thisLocation/') {
alert('Back Pressed: ' + String(location.pathname));
} else {
alert('Refreshed: ' + String(location.pathname));
}
}
});
this.setState({ ...this.state, unlisten: unlisten });
}
componentWillUnmount() {
this.state.unlisten();
}
You can see more details in the link provided by Rei Dien as a comment of your question: https://www.npmjs.com/package/history
[EDIT]
Another way to do this is using https://www.npmjs.com/package/react-router-last-location and doing this:
import { useLastLocation } from 'react-router-last-location';
componentDidMount() {
const unlisten = history.listen((location, action) => {
const lastLocation = useLastLocation();
if (location.pathname == lastLocation.pathname) {
alert('Back Pressed: ' + String(location.pathname));
}
}
});
this.setState({ ...this.state, unlisten: unlisten });
}
componentWillUnmount() {
this.state.unlisten();
}
The downside is that there is no difference between activating the back action or clicking in a link that goes to the page that you was before, both would be detected as pressing back. If you don't want a new dependency, you can do it manually as stated in https://github.com/ReactTraining/react-router/issues/1066#issuecomment-412907443 creating a middleware.
I think this will at least point your in the right direction. Navigate to yourwebsite.com.
let current_page = history.state.key
if(history.action == 'POP') {
if(history.state.key == current_page) {
return 'page was refreshed'
}
return 'back button was pressed'
}
I'm using History.js (the jquery.history.js v1.8b2). Chrome version 30.0.1599.101 m.
I can't figure out how to make History.js work the way I'd expect.
I have a page that has two links. The first simulates an ajax operation. It just changes the text in an <h2> in the page from "start" to "2". The second link just points to google.com.
Here's what I do:
Clear cache in chrome
Load the page
Click the first link (I call pushState, statechange occurs and there I update my text to "2")
Click the google.com link (goes to google)
Click the browser Back button.
Upon back button click, I expect that the statechange handler should be called and I would then get my state object so I could restore the text to "2".
But the handler is not called. So my page is left with text "start" (the cached page in the browser). Interestingly, the url is set to the "2" version that I pushed in my pushState call.
Am I missing something? Here is my code:
<h2 id="state">start</h2>
<a id="2" class="button" href="#">Goto State 2</a>
Goto google
<script type="text/javascript">
$(function() {
History.Adapter.bind(window, "statechange", function() {
console.log("statechange called");
var state = History.getState();
if (state.data.mystate) {
// Restore the old state
$("#state").text(state.data.mystate);
} else {
// Start state
$("#state").text("start");
}
});
$(".button").click(function(e) {
// push the state we're transitioning to
var newState = $(this).attr("id");
History.pushState(
{ mystate: newState },
"at state " + newState,
"http://localhost:50494/PushState?state=" + newState);
// statechange will be called now, and we'll update the page from our newState
e.preventDefault();
});
});
</script>
I think the answer is no, the statechange isn't supposed to be called when navigating back from outside the page.
I noticed that the demo at http://browserstate.github.com/history.js/demo/ was working as I'd expect, so I did a view source to see how it was working. From what I can tell, here is how you are supposed to use History.js.
When your page loads, you look at History.getState().data. If you recognize one of your states there, then it means you are navigating back into your page from a different page, like from an external link you went to. (Note: the browser may have just loaded your page from cache or it could have been reloaded from the server. Shouldn't matter because you're going to update the page/ui with the state you just found). So, update your page to that state. If you didn't recognize the state, then it's a first time load as far as your page is concerned. Init appropriately.
The statechange event will get called upon the browser back/forward button between "ajax" states within your page (states you've pushed while in this one page). It will also get called when you call pushState(). Huh, isn't that confusing? Yes, so when you want to transition to a new state within your page, follow this pattern:
Prepare your state object (could involve an ajax call),
Call pushState(yourObject,...)
Don't update your page/ui yet.
You actually update your page/ui from the statechanged handler that's gonna get called in a moment.
I mistakenly thought you were supposed to do all the work of updating the page, then push the state afterward. This will just make things hard, since statechanged is gonna get called too.
Also, it appears that in general, you should push states for ajax-like transitions within the one page you're on. Don't push states for links you follow outside the page (unless you really understand all this and are trying to do something fancy).
I've updated the sample code here to show what's working for me now:
<h2 id="state">start</h2>
<a id="2" class="button" href="#">Goto State 2</a>
Goto google
<script type="text/javascript">
$(function () {
// page loading, check for available state I recognize
var availableState = History.getState();
if (!availableState.data.mystate) {
// loading for the first time
$("#state").text("start");
} else {
// load from the available state
loadState(availableState);
}
History.Adapter.bind(window, "statechange", function () {
var state = History.getState();
loadState(state);
});
function loadState(state) {
if (state.data.mystate) {
// update the page to this state
$("#state").text(state.data.mystate);
} else {
// update the page to the initial state
$("#state").text("start");
}
}
$(".button").click(function (e) {
// The user clicked a button, so we want to transition to a new state
// in this page. Push the state we're transitioning to (which we've hidden
// in the id attribute in this example).
var newState = $(this).attr("id");
History.pushState(
{ mystate: newState },
"at state " + newState, // title
"?state=" + newState); // url
// statechange will be called now, and we'll update the page from our newState
e.preventDefault();
});
});
</script>