Aurelia - Update the menubar once a user has logged out - aurelia

I have navmenu that needs to reloaded after a user logs out.
I have a logout.ts that essentially clears the JWT and loggedIn value.
import { autoinject } from "aurelia-framework";
import { TokenService } from "../../auth/tokenService"; z
import { Router } from 'aurelia-router';
#autoinject
export class Logout {
constructor(private tokenService: TokenService, public router: Router) {
tokenService.clearJWT();
this.router.refreshNavigation()
}
}
Thats all fine but I wanted to redirect to the home page but at the same time update the menu this time rechecking for loggedIn status.
I tried redirect, I have tried:
this.router.navigateToRoute('home')
and the one above. In all cases the navmenu does not update. By updating the navmenu it will check for a loggedin value in localstorage and change the structure of the menu.
I also wanted it to go the home page after removing those items but more importantly how do I get it to refresh the navmenu?

It sounds like you need to make sure your home route is refreshed even though it is already the current route. If so, in your configureRouter method, add activationStrategy.replace:
import {activationStrategy} from 'aurelia-router';
export class MyClass {
configureRouter(config) {
config.map([{
route: 'home',
name: 'home',
activationStrategy: activationStrategy.replace,
title: 'My Title',
moduleId: 'myModule',
}]);
}
}

Related

How to show login page by default after logout?

I want to show my login screen after logout.
Currently without LogoutModule after logout my page is redirecting to a blank screen and if I implement it as per the documentation, it redirects to homepage.
Documentation reference: https://sap.github.io/spartacus/modules/LogoutModule.html
#NgModule({
imports: [
PageLayoutModule,
RouterModule.forChild([
{
path: null,
canActivate: [LogoutGuard, CmsPageGuard],
component: PageLayoutComponent,
data: { cxRoute: 'logout' },
},
]),
],
})
I have tried protecting my homepage, however if I do that, I am unable to logout at all i.e. nothing is happening if I click logout.
You can achieve this by overriding the default getRedirectUrl from LogoutGuard.
Currently, the base class redirects to login page upon logout if and only if it's a closed shop. Meaning, the user must login before doing any action (early login).
An example of how to override the LogoutGuard behavior is to do the following:
1 - create your custom logout guard
#Injectable({
providedIn: 'root',
})
export class NewLogoutGuard extends LogoutGuard {
constructor(
auth: AuthService,
cms: CmsService,
semanticPathService: SemanticPathService,
protectedRoutes: ProtectedRoutesService,
router: Router,
authRedirectService: AuthRedirectService
) {
super(
auth,
cms,
semanticPathService,
protectedRoutes,
router,
authRedirectService
);
}
protected getRedirectUrl(): UrlTree {
return this.router.parseUrl(this.semanticPathService.get('login'));
}
}
2 - aliasing the class providers by providing the new logout guard
{ provide: LogoutGuard, useExisting: NewLogoutGuard },

How to include a specific component in $router.push()?

I have a click event like so:
cancelEdit(){
this.$router.push({path: '/path/abc'})
}
The user is sent to a new "page" after click. However, is it possible to also load a specific component when he arrives to the new path? I thought I'd do something like:
import ComponentHere from '#/components/ComponentHere.vue'
export default {
..snip..
methods: {
cancelEdit() {
this.$router.push({ path: '/admin/feedback-maintenance', component: ComponentHere })
}
This did not work in my attempt.

Ionic v4 `menuController.enable` method not working on first page loaded

I use a sidemenu project with ionic v4-beta3
I want to disable sidemenu on some pages, /login for example.
It's working properly when i load /home page first then i navigate to /login page. Sidemenu desapear as expected.
When i reload my application on /login page, menu is not disabled.
import { Component, OnInit } from '#angular/core';
import { MenuController } from '#ionic/angular';
#Component({
selector: 'app-login',
templateUrl: './login.page.html',
styleUrls: ['./login.page.scss'],
})
export class LoginPage implements OnInit {
constructor(
private menuController: MenuController
) {}
ngOnInit() {}
ionViewWillEnter() {
console.log('ionViewWillEnter');
this.menuController.enable(false);
}
ionViewDidLeave() {
console.log('ionViewDidLeave');
this.menuController.enable(true);
}
}
If a use a setTimeout of 100 or 200 ms to call enable method, side menu desapears but it's not very clean...
ionViewWillEnter() {
console.log('ionViewWillEnter');
const timer = setTimeout(() => {
clearTimeout(timer);
this.menuController.enable(false);
}, 100);
}
Another work-around is to show ion-menu when window.location.pathNameis not equal to /login with a *ngIf directive. It's working but i find this not very clean too...
Ionic Infos
Ionic:
ionic (Ionic CLI) : 4.1.1
Ionic Framework : #ionic/angular 4.0.0-beta.3
#angular-devkit/core : 0.7.4
#angular-devkit/schematics : 0.7.4
#angular/cli : 6.1.4
#ionic/ng-toolkit : 1.0.6
#ionic/schematics-angular : 1.0.5
This issue appears to be resolved in 4.0.0-beta.12 with the following:
ionViewDidEnter() {
this.menuController.enable(false);
}
ionViewDidLeave() {
this.menuController.enable(true);
}
The MenuController.enable() method is asynchronous.
You can create a Guest/Authenticated guard and enable it there, and then use it in pages using the canActivate route parameter in your pages. Then, when your page loads, the menu will be configured properly. For example, for authenticated guard:
#Injectable({
providedIn: 'root',
})
export class AuthenticatedGuard implements CanActivate {
constructor(private menuController: MenuController) {}
async canActivate(): Promise<boolean> {
const isAuthenticated = true; // Adjust where you get this value
await this.menuController.enable(isAuthenticated);
return isAuthenticated;
}
}
This will work for Ionic4/5.
You should use menuId property in your <ion-menu/> components for fine-tune identity and be able to use multiple menus. Then you can call .enable(isAuthenticated, menuId);

Screen Freezing when Setting Multiple Roots

When my aurelia app starts I send them first to the login page and check and see if they are logged in and if so, set set the root to app, otherwise, have them log in.
aurelia.start().then(() => aurelia.setRoot(PLATFORM.moduleName("modules/login")));
This should work, according to everything I could find. It does actually set the root to as far as the code is concerned as I see activity in the console, but the html on the screen never moves from the login screen. Even typing something manually in the address bar does not change the html. So it seems the router has stopped functioning. No errors are logged in the console.
import { AuthenticateStep, AuthService } from 'aurelia-authentication';
import { Router} from 'aurelia-router';
import { autoinject, PLATFORM, Aurelia } from "aurelia-framework";
#autoinject()
export class Login {
constructor(private router: Router, private authService: AuthService, private aurelia:Aurelia) {
console.log("Starting Login...")
}
activate() {
if (this.authService.authenticated) {
console.log("is authenticate")
this.router.navigate('/', { replace: true, trigger: false });
console.log("setting root to 'app'");
this.aurelia.setRoot(PLATFORM.moduleName("app"));
}
else {
console.log("not auth");
}
}
}
In app.ts
activate() {
console.log("app.activate");
...
}
Is there something else I should be doing?
I have tried: https://github.com/aurelia/framework/issues/400
And this: https://ilikekillnerds.com/2017/07/aurelia-routing-switching-root-using-setroot/
Here are a few things you can try:
Chain the promises (make sure the navigation is done before you tell aurelia to switch the root)
this.router.navigate('/', { replace: true, trigger: false })
then(() => this.aurelia.setRoot(PLATFORM.moduleName("app")));
Resolve the promises (would be necessary if the router still has work to do after the current activate because that work would need to be aborted)
return this.router.navigate('/', { replace: true, trigger: false })
then(() => this.aurelia.setRoot(PLATFORM.moduleName("app")));
Verify that the AppRouter is reconfigured after you switch root (breakpoint in configureRouter, you may need to manually .reset() the router is the isConfigured flag is somehow still true)
You could try a different approach altogether.
Personally when I need to switch root between a public and an authenticated shell, I just have a dedicated path prefix for either (or both) and in my main method I set the root to the correct App based on the current window.location.
Example (in main):
if (/\/public/.test(window.location.pathname)) {
au.setRoot(PLATFORM.moduleName("shell/public"));
} else if ((/\/admin/.test(window.location.pathname)) {
au.setRoot(PLATFORM.moduleName("shell/admin"));
} else {
au.setRoot(PLATFORM.moduleName("shell/app"));
}
Redirecting between these roots goes outside of the router, simply with window.location.href = "...";
Although it's arguably a little hacky, the nice thing about the approach is that you'll always have a completely clean Aurelia state after switching, and thus less you potentially need to clean up after.
In the non-public roots, you try to grab the auth token from localStorage and simply kick the user back to public if there is none (or they don't have sufficient privileges).
Setting the root is quite easy, but there is a caveat:
Set it either in response to a user generated event, or in the attached event.
Attempting to set it in the activated event or constructor will result in the screen becoming frozen on the root screen.
This took me pretty much a day to figure out, so I thought I would pass it on.
Here is what worked for me: I created a "app-shell" which is set to the root by main.
In app-shell, I check whether or not the person is already logged in, and then I set the root depending on the results.
import { AuthenticateStep, AuthService } from 'aurelia-authentication';
import { AppRouter } from 'aurelia-router';
import { autoinject, PLATFORM, Aurelia } from "aurelia-framework";
#autoinject()
export class AppShell {
constructor(private router: AppRouter, private authService: AuthService, private aurelia: Aurelia) {
}
attached() {
this.setRoot();
}
setRoot() {
this.router.navigate('/', { replace: true, trigger: false }); //Not actually needed here, but is if the router has already been configured.
if (this.authService.authenticated) {
this.aurelia.setRoot(PLATFORM.moduleName("app"));
}
else {
this.aurelia.setRoot(PLATFORM.moduleName("modules/login"));
}
}
}

Handle a request with a specific function in a component

We are developing a component that handles OpenID Connect's implicit flow.
In step 5 of the flow, the "Authorization Server sends the End-User back to the Client with an ID Token and, if requested, an Access Token." We would like our component to handle that request, which will be to ~/openid-login.
How do we configure Aurelia to have it route to a function in our component?
export class OpenId {
// how do we route ~/openid-login to this?
public handleRequest() {
}
}
Note: Here is the work in progress.
Using a navStrategy within your routeConfig will allow you to do what ever you like before navigating to a page. See below:
import { autoinject } from 'aurelia-framework';
import { RouterConfiguration, Router, NavigationInstruction } from 'aurelia-router';
#autoinject
export class App {
router: Router;
configureRouter(config: RouterConfiguration, router: Router) {
let openIdNavStrat = (instruction: NavigationInstruction) => {
console.log('Do whatever we would like to do.');
// then redirect to where ever you would like.
instruction.config.moduleId = 'login';
}
config.map([
{ route: ['', 'login'], moduleId: 'login' },
{ route: 'openid-login', navigationStrategy: openIdNavStrat },
]);
this.router = router;
}
}
There is documentation on Navigation Strategies here: http://aurelia.io/hub.html#/doc/article/aurelia/router/latest/router-configuration/3