Cannot perform routing with pushstate and various js routers - javascript

I am not sure if I understand well the situation with pushstate and routing but I am stuck trying to route a single page app using either pagejs or grapnel or other similar javascript routers.
What I want is to be able to navigate through my program and through manually entering routes in the location bar (so I can send links to various parts of my spa to third parties). I cannot navigate manually to the /test route for example with the below code.
The following is an example with pagejs.
I have also made my nodejs backend to redirect to /#login if it gets a request for /login.
How can I utilize pushstate so that I can both enter a manual address in the location bar and navigate through it from the router and html links?
What am I missing here?
Some sample code:
page('/',index);
page('/signin',signin);
page('/test',test)
page();
function index() {
console.log('in index')
new WelcomeView();
console.log('rerouting');
page('/signin');
}
function signin() {
console.log('in signin')
//new SigninFormView();
}
function test() {
console.log('in test');
}
in welcome.html
click lets see
in app.js (server side)
//router redirect to webapp
app.use(function(req, res, next) {
const redirectUrl=(req.secure ? 'https://' : 'http://') + req.headers.host +'/#'+req.originalUrl.substring(1);
res.redirect(redirectUrl);
});
This has the following outcomes:
1) navigating to / I get the welcome page and a console log that it has navigated to the signin route
2) writing the link manually /signin in the location bar I again navigate to the / route which redirects
3) writing the link manually /#signin in the location bar I again navigate to the / route which redirects
4) clicking the link in the welcome.html again redirects me through the / route
5) clicking the link in welcome.html and changing it to /test works.

Whenever you (manually or otherwise, usually by setting window.location = 'myurl') change anything in the address bar, the browser will always make a request for that, afaik there is no way around it, and if there was, it would be a security issue, as pages could hijack your browser, by not allowing to navigate away to any other url. If you want to be able to load a particular url in your SPA by typing it in the location bar, you need the server to respond with something. In an SPA, you would typically return the same html that loads your SPA. Now, it seems like pagejs doesn't' respect the url in the location bar, and keeps loading / (I believe I've seen that before), as a workaround, you can try setting page() to window.location.pathname when your app loads, and see if that will fix your second issue.
Also, hashbang urls, arent enabled by default with page, you need to enable them with page({hashbang: true}).

Related

Prevent navigation to certain pages/routes

I have a Next.js (fix may not necessarily have anything to do with Next.js) app that I want to limit some navigation. This page in the Next.js docs mentions "you should guard against navigation to routes you do not want programmatically", but I'm unsure how to do this. Let's say I have the following pages:
/bikes
/boats
/cars
and I only want to allow a user to see /bikes. How would I be able to do this. I'm able to redirect from an undesired page to an acceptable page, but only after the undesired page loads. Is there a way to redirect before this (maybe by changing the URL as soon as it is changed)?
I appreciate that this is an old question, however, I wish I had known this answer to it earlier than I did, so I would like to answer it for the record.
Our next.js app had a relatively complex set of permissions associated with accessing each page (with the ability to access the page, or different data presented on it) based on the authentication status of a user as well as the authorization scopes granted to them.
The solution that we used was the to return a redirect from getServerSideProps(). Normally one would return something like the following:
const getServerSideProps = (context) => {
return {
props: {
myProp: 1
}
};
}
However, it is also possible to return a redirect. This redirect is performed on the server side prior to the page content being sent to the browser:
const getServerSideProps = (context) => {
return {
redirect: '/login'
};
}
This is relatively new functionality - it was only pulled in towards the end of last year, and there isn't much documentation for it anywhere, but it perfectly serves this use case.

How to programmatically navigate with preact-router?

I'm trying to figure out how to structure the frontend part of a web application using typescript, preact and preact-router. I've come a long way but I still need to figure out how to programmatically navigate (redirect) with preact-router. I can do history.replaceState(null, null, '/#/redirectedUrl');, but while that changes the URL in the location bar, preact-router doesn't route to the new URL.
What is the preferred way to programmatically navigate when using preact-router?
Importing the function route from 'preact-router' is the way to go:
import { route } from 'preact-router';
route('/url/to/rout/to');
You can do it in two ways based on your need
import { route } from 'preact-router';
route('url');
This will create a pushState in the history (i.e.,) it will create a new entry for this url
import { route } from 'preact-router';
route('url', true);
This will create a replaceState in the history (i.e.,) this will replace the current page url entry in the history with the url you will be routing to. You can make use of this in cases like, when routing from login screen to your home/dashbaord screen, where on click of browser back button, you don't want user to go back to login screen once the user has been logged in (thus replacing the login entry with your dashbaord entry).

Meteor push/browserhistory won't go/reload to new page

So i am trying to make it so when the user hit one of the profiles, they get pushed to the profile page of the user the click on.
I am using currently using this set of code:
const self = this;
browserHistory.push({
pathname: '/users/' + self.props.user.username,
state: {_id: self.props.user._id}
});
Which just enter the correct url in the url bar. Although, the page does not load/reload. So i manually have to reload the page to get into the userprofile
Thank you for your time and help
tl;dr
You have to use a router which works properly with Meteor, right now FlowRouter is the best option to go
Reloading the page is not the expected behavior when route changes in Meteor, only the content of the page should be change to match the new route. Because apps created by Meteor are Single-page application, meaning that all content/code of your app are loaded at your first load.
After the first load, all required code for your app to work are already in client so when route changes the required content will be compute and put on the page, no request will be send to server.

What is the use of HTML5 pushState in Backbone History Start method

I have a simple Backbone app. I am trying to understand the difference created by passing pusState: true when starting Backbone.History object.
JavaScript
var r = new (Backbone.Router.extend({
routes: {
"users": "allUsers",
"users/new": "createUser"
},
allUsers: function () {
v.render("showing all users");
},
createUser: function () {
v.render("showing form for creating new user");
}
}));
Backbone.history.start({ pushState: true });
Q1. When I pass pushState: true and I open localhost:3000/#/users/, this url automatically redirects to localhost:3000/users
Why does this redirect happen ?
Q2. When I do not pass pushState: true then redirect does not happen.
localhost:3000/#/users/ works fine but localhost:3000/users does not work ?
What is importance of passing this value in history.start method and why is it important.
Including the pushState option when starting Backbone.history tells Backbone to use the HTML5 history API. Basically, this API lets you change the URL in the address bar without reloading the page (see more about it here). Without pushState, Backbone will use hashes (#) to change the URL, so it doesn't have to reload the page.
When I pass pushState: true and I open localhost:3000/#/users/, this url automatically redirects to localhost:3000/users Why does this redirect happen ?
Since you've enabled the history API, Backbone will choose to use actual routes (localhost:3000/users) instead of hashed routes (localhost:3000/#/users/). However, it still understands the hashed routes, so it redirects them to the actual route. This way, if you enabled pushState in an existing application, any user who has a hashed route bookmarked will still be able to use that bookmark. (And of course, any new bookmarks will have the right route).
When I do not pass pushState: true then redirect does not happen. localhost:3000/#/users/ works fine but localhost:3000/users does not work ?
Answer to Q2: When pushState is not enabled, Backbone will only use hashed routes. So localhost:3000/#/users/ doesn't redirect because it is the "right" route: it will display the content. Depending on how you've set up your server, localhost:3000/users will either
Load your app but show no content (or default content)
Load whatever the /users resource is, OR
Give you a 404 error.
When using pushState, you're telling your Backbone application to fetch the HTML from the backend at the defined URL (without hash). This means that your backend needs to be prepared for that, which is why the localhost:3000/users doesn't work by default if you didn't foresee a backend resource. Fetching the HTML from the backend happens without page refresh though, so it doesn't interrupt the JS from running.
When using the hash without pushState, you're using the front end router (hashed routes) and its callbacks only, and no request to the backend is made.

Node.js and Express - Redirect after Login and Download

I have an express app that allows a user to login and download data files. There is also a home page after the login. If a user enters the URL to a specific file without logging in, the app will first ask the user to login, which is by design. However, after the user logs in, the file is downloaded without redirecting the user to the home page. I was wondering if there's a way to allow the user to login, redirect to the home page, and then download the file with one click after the user logs in. It's kind of confusing now because the user is stuck on the login page after successfully logging in and downloading the file. Below is a snippet of the code. I am using express 4.x:
app.get('/dat/:file(*)', routes.ensure_authenticated, function(req, res, next) {
var path = __dirname + '/public/dat/' + req.params.file;
res.download(path);
});
app.use('/', serveStatic(__dirname + '/public'));
// dat directory requests
app.use('/dat', routes.ensure_authenticated, serveIndex( 'public/dat', { icons: true }));
I can't think a way of doing it server-side only.
You could trigger client-side the redirection to the download.
Something like redirecting to /#download=link_or_id and parsing the hash with JavaScript to get the final download link (the link_or_id thing). Then, after the download is triggered, remove the hash from location so the download isn't triggered again when the user reloads the page.
Also, instead of using JavaScript, you could do something similar redirecting to /?download=link_or_id and server-side inserting a meta refresh tag inside <head>.
You could programmatically send an ajax GET request from the client side via a setTimeout or on document load, so it would be something like:
$(function() {
$.get('/dat/filename', function(){
//enter code here
});
}):

Categories

Resources