The main router's pipeline of my application redirects to login page if a user is not logged in.
It works fine for most pages, but when said page holds itself a child router, the logic does not seem to hit the main router's pipeline, preventing redirection (as well as not rendering the page).
main router:
configureRouter (rc: RouterConfiguration, router: Router) {
this.router = router;
rc.addAuthorizeStep(this.requireAuth);
const auth = { authenticated: true, needsCurrentOrg: true };
const loginRoute = {
route: 'login/:token?',
name: 'login',
moduleId: PLATFORM.moduleName('views/login/login'),
};
rc.map([
{
route: [ROOT_PAGE, DASHBOARD_PAGE],
name: DASHBOARD_PAGE,
moduleId: PLATFORM.moduleName('views/dashboard/dashboard'),
settings: auth
},
{
route: CREDENTIALS_PAGE,
name: CREDENTIALS_PAGE,
moduleId: PLATFORM.moduleName('views/credentials/credentials-root'),
settings: auth
})]
}
credentials router:
configureRouter (rc: RouterConfiguration) {
rc.map([
{
route: '',
name: 'credentials-list',
moduleId: PLATFORM.moduleName('./credentials-grid'),
}
]);
}
So if I hit /#/dashboard without being logged in, I get redirected to /login, but nothing happens if I hit /#/credentials: blank page, no redirection. I put a debugger in the requireAuth middle-ware code, and in the first case it does step in, in the second case it does not go through
Finally identified the issue, for some reasons it looks like the LoadRouteStep pipeline step (internal to the AppRouter) tried to load the ViewModel of the subrouter target.
Since this ViewModel had some code in the constructor, that code was failing, creating an error and stopping the pipeline - never reaching the redirection.
The fix was to move that constructor code into an activate function for the ViewModel.
Related
I'm currently working on porting the following router.beforeEach action that I have for a Vue.js application to something workable within Nuxt.js.
I've had a good trawl of the middleware documentation, but I'm not quite sure what the correct pattern would be to follow.
My callback which runs before every route change in my Vue.js application is as:
// This callback runs before every route change, including on page load.
router.beforeEach(async (to, from, next) => {
// Reset All State When A User Logs Out:
if (to.redirectedFrom === '/sign-out') {
store.dispatch('auth/resetAuthState')
Vue.prototype.authAPI.cleanseLocalStorage()
}
if (to.meta.authenticationRequired) {
if (!store.getters['auth/activeUserIsAuthenticated']) {
next({ name: 'signIn' })
} else {
next()
}
} else {
next()
}
})
I have the following redirect in my Vue router to perform the redirect action:
...
{
path: '/sign-out',
name: 'signOut',
redirect: {
name: 'signIn'
},
meta: {
...{
authenticationRequired: false,
sitemap: {
ignoreRoute: true
}
}
}
},
...
So on a SignOut redirect, I cleanse local storage and do some further state management inside the Vuex store.
However, I have no idea where to start this with Nuxt.js - any ideas would be greatly appreciated.
I suggest that using "Nuxt/auth" for handling your authentication. you can read this docs here:
https://auth.nuxtjs.org/
On a Nuxt.js project I worked on, I created a sign-out.vue page and emptied the localstorage from there, then redirected to the homepage.
I'm trying to redirect to a route/URL and append a hash at the end, but Aurelia keeps telling me ERROR [app-router] Error: Route not found: /#the-hash-i-added.
Here's the very basic code I'm using to redirect to a new route inside my authorize pipeline step:
return next.cancel(new Redirect(this.router.generate('home')));
This works fine and redirects non authorized users to the home page. However, I'd like them to end up at one specific part on the home page, hence the hash.
Now, since the Redirect class takes a URL as its argument, I figured I'd simply add the hash at the end, like so:
return next.cancel(new Redirect(this.router.generate('home') + '#hash-where-i-want-to-end-up'));
And while Aurelia successfully redirects to the correct URL (/#hash-where-i-want-to-end-up is set in the browser's URL bar) it still throws the aforementioned error and does not render the page.
I actually managed to hack around this by manually adding the hash after the redirect occurred, with a setTimeout:
setTimeout(() => {
window.location.hash = '#hash-where-i-want-to-end-up';
});
return next.cancel(new Redirect(this.router.generate('home')));
But not only does this feel like a dirty, dirty hack, it doesn't work well in other scenarios.
So, my question is, how can I redirect to a route and append a hash at the end?
Needless to say I'm using pushState: true and hashChange: false in my application.
Edit: I couldn't get a pushState app running on gist.run for some reason, but I set up a completely new Aurelia CLI project with this very basic setup:
app.js
import {inject} from 'aurelia-framework';
import {Router, Redirect} from 'aurelia-router';
export class App {
configureRouter (config, router) {
config.title = 'Test';
config.options.pushState = true;
config.options.hashChange = false;
config.options.root = '/';
config.map([
{
route: [''],
name: 'home',
moduleId: 'resources/elements/home',
title: 'Home'
},
{
route: ['about'],
name: 'about',
moduleId: 'resources/elements/about',
title: 'About',
settings: {auth: true}
},
]);
config.addAuthorizeStep(AuthorizeStep);
}
}
#inject(Router)
class AuthorizeStep {
constructor (router) {
this.router = router;
}
run (navigationInstruction, next) {
// Never allow access to auth routes
if (navigationInstruction.getAllInstructions().some(i => (i.config.settings && i.config.settings.auth))) {
return next.cancel(new Redirect(this.router.generate('home') + '#foo'));
}
return next();
}
}
app.html
<template>
<a route-href="route: home">Home</a> | <a route-href="route: about">About</a>
<router-view></router-view>
</template>
home.js
export class Home {}
home.html
<template>
<h1>Home</h1>
</template>
about.js
export class About {
}
about.html
<template>
<h1>About</h1>
</template>
As you can see, going to /about should redirect you back to /#foo, and while that indeed works (the user ends up at /#foo) I get the same error: vendor-bundle.js:14169 ERROR [app-router] Error: Route not found: /#foo
I'm having a really hard time to figure out how to load a particular route when the activate event is fired. I'm creating an Electron application using the Electron-Vue framework and I've these following routes:
export default [
{
path: '/',
name: 'login-page',
component: require('components/LoginPageView')
},
{
path: '/tracker',
name: 'tracker-page',
component: require('components/TrackerPageView')
},
{
path: '*',
redirect: '/'
}
]
Now, I'd like to load the /tracker route once the app.on('activate') is fired on the following:
app.on('activate', () => {
if (mainWindow === null) {
createWindow()
}
})
The main reason behind this is I'm creating a two window Electron application. The first window would be the login and the second window would be user profiles. When the user already logged in and closed the app using the system close button, the app stays in the Dock bar and when the app is clicked, the Electron activate event is fired and the login screen shows again. Since the user is already logged in, I don't want the user to show the login window again. Any suggestion would be must appreciated.
I was finally able to achieve this by using the Vue-Router Per-Route Guard beforeEnter method. Here's my draft:
let auth = true
export default [
{
path: '/',
name: 'login-page',
component: require('components/LoginPageView'),
meta: {
auth: false
},
beforeEnter: (to, from, next) => {
if (auth) {
next('/tracker')
} else {
next()
}
}
},
{
path: '/tracker',
name: 'tracker-page',
component: require('components/TrackerPageView'),
meta: {
auth: true
}
},
{
path: '*',
redirect: '/'
}
]
Any feedbacks are most welcome to improve this even better :)
I am trying to configure Durandal child routing. I have a public section for witch the parent router is responsible:
//main router
return router.map(config.publicRoutes)
.buildNavigationModel()
.mapUnknownRoutes('account/login', '#login/')
.activate();
//public routes
[{ route: 'login', title: 'Login', moduleId: 'account/login', nav: false, hash: '#login/' },
{ route: 'register', title: 'Register', moduleId: 'account/register', nav: false, hash: '#register/' },
{ route: 'reset-password', title: 'Reset password', moduleId: 'account/reset-password', nav: false, hash: '#reset-password/' },
{ route: 'private*details', moduleId: 'private/private-shell', title: 'Application', nav: true, hash: '#private/' }
];
Then a child router should be responsible for the private section. I am mapping the routes for the child router after the user has logged in. Depending on the user type (admin, user) I am activating the child router with the appropriate routes:
//initializing the router from the login view
var promise = Q.all([private_shell.initRoutes(isAdmin || true)]);
return promise.then(navigate("#private/silos"));
// child router in private-shell
var privateRouter = router.createChildRouter();
var routes = [];
//method to initialize the proper routes after login
var initRoutes = function (isAdmin) {
privateRouter.reset().makeRelative({
moduleId: 'viewmodels/private/',
fromParent: true
});
console.log(privateRouter);
return privateRouter.map(isAdmin ? config.adminRoutes : config.userRoutes).buildNavigationModel();
};
The first time when the router is initialized all works fine but if I return to the main router(login view) and another login is performed the child router adds the relative moduleId twice.
After the first login the routes have the moduleId ´viewmodels/private/route´, which is the right one, but second time the login initializes the child router the routes have the moduleId ´viewmodels/private/viewmodels/private/route´.
GET http://localhost:7777/App/viewmodels/private/viewmodels/private/silos.js 404 (Not Found)
When it should be:
GET http://localhost:7777/App/viewmodels/private/silos.js
I wasn't able to identify what might cause this. Any help?
Can you try specifying the parent route in a route property on the makeRelative settings object?
Perhaps also try making the reset call explicit.
Like this:
privateRouter.reset();
privateRouter.makeRelative({
moduleId: 'viewmodels/private/',
fromParent: true,
route: 'viewmodels/private'
});
I'm getting "Route not found" in the console window on trying to load an app converted from 1.2 to 2.0. Is there any way I can debug what route it's trying to find at the point of failure please? It would be handy if it said, "cannot find route:/viewmodels/wrongfolder/startup" or something!
Please be aware that ALL of this was working perfectly prior to upgrading from 1.2 to 2.0, so it's differences in the Durandal settings that I need to address. No files have been removed or lost or moved, so it's not that things have changed in the app outside of the new versions of scripts being updated by nuget.
main.js and config.js live in root of "app" folder. Shell.js is in app/viewmodels and shell.html is in app/views. All views/viewmodels are in the relevant folders below the main /app folder.
I have a "config.js" file with routes returned:
var routes = [{
route: 'home',
moduleId: 'home',
title: 'Home',
nav: true
}, {
route: 'labTool',
moduleId: 'labTool',
title: 'Lab Tool',
nav: true
}];
var startModule = 'labTool';
main.js:
//specify which plugins to install and their configuration
app.configurePlugins({
router: true,
dialog: true,
widget: false
});
app.start().then(function () {
viewLocator.useConvention();
router.makeRelative({ moduleId: 'viewmodels' });
app.setRoot('viewmodels/shell');
router.handleInvalidRoute = function (route, params) {
logger.logError('No route found', route, 'main', true);
};
});
Shell.js:
var inEditMode = ko.observable(false); //set edit mode to false at start
var shell = {
activate: activate,
router: router,
inEditMode: inEditMode
};
return shell;
function activate() {
return datacontext.primeData()
.then(boot)
.fail(failedInitialization);
}
function boot() {
logger.log('Application Loaded!', null, system.getModuleId(shell), true);
router.map(config.routes).buildNavigationModel();
return router.activate(config.startModule);
}
function failedInitialization(error) {
var msg = 'App initialization failed: ' + error.message;
logger.logError(msg, error, system.getModuleId(shell), true);
}
Some of the code may still need editing to handle the change from 1.2 to 2.0 but I think I have most of it now.
I had a similar problem after the upgrade and creating a default route with a route property of '' sorted it for me.
So instead of using your startModule property try setting you labTool route to have a route property of ''.
In case anyone else runs into this, this error can also occur if you have non-ascii characters in the route name.
Not working:
{ route: 'Møøse', ... }
Working:
{ route: 'Moose', title: 'Møøse', ... }