9

I'm using Angular 6 and I have an issue with the change of routes. If I navigate through the application using the routerLink or the navigate() method, it works correctly, because it only load the new module (if necessary). But for example if I am in this link: localhost:8080/home, I click on the URL, cancel the 'home', write 'profile' and press Enter, it correctly goes on profile page but the application in reloaded (also the app component). Why? I can't figure out. This is my routing:

const appRoutes: Routes = [
  { path: 'home', component: HomeComponent, canActivate: [AuthGuard] },
  { path: 'profile', component: ProfileComponent, canActivate: [AuthGuard] },
  { path: 'login', component: LoginComponent },
  { path: '', redirectTo: 'home', pathMatch: 'full' },
  { path: '**', component: PageNotFoundComponent }
];

@NgModule({
  imports: [
    RouterModule.forRoot(appRoutes, { preloadingStrategy: PreloadAllModules })
  ],
  exports: [RouterModule]
})
export class AppRoutingModule { }

Maybe the issue is on the auth-guard?

@Injectable()
export class AuthGuard implements CanActivate {

constructor(private store: Store<fromApp.AppState>, private route: ActivatedRoute, private router: Router) {
}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
    return this.store.select('auth')
        .pipe(take(1),
            map((authState: fromAuth.State) => {
                if (authState.authenticated) {
                    return true;
                } else {
                    let sessionStorageToken: string = sessionStorage.getItem('token');
                    if (sessionStorageToken) {
                        this.store.dispatch(new AuthActions.Login());
                        this.store.dispatch(new AuthActions.SetToken(sessionStorageToken));
                        return true;
                    } else {
                        let url = state.url;
                        this.router.navigate(['/login', { redirectTo: url }]);
                        return false;
                    }
                }
            }));
}
}

This is profile.module.ts:

@NgModule({
declarations: [
    ProfileComponent
],
imports: [
    CommonModule,
    FormsModule
]
 })
 export class ProfileModule { }
panagulis72
  • 2,129
  • 6
  • 31
  • 71
  • You have to hit enter twice. I don't know why, I have never looked into it. Is there a purpose after that ? What do you want to achieve ? –  Jul 04 '18 at 08:13
  • This is my first project in Angular, usually I used AngularJS..and in AngularJS if, for example, i'm in home, then i go to profile, and then i go to home (also manually by the url) the page and the application is not realoded! The problem is that I'm using Redux to manage the state and the logged user, so if I go to "profile" page and the app si reloaded, I lose the part of State regarding the logged user – panagulis72 Jul 04 '18 at 08:16
  • For anyone who has put a vote down: I'm glad that this problem has never happened to you. – panagulis72 Jul 04 '18 at 08:17

5 Answers5

6

you can use

RouterModule.forRoot(
  ROUTES,
  { useHash: true }
)],

The hash will prevent application from reloading. So when you will hit enter on address bar, application will just change the component to display.

LETOURNEUR Léo
  • 283
  • 3
  • 11
  • It works fine (Angular 12), it's what I was looking for ... !! This reload caused the information in memory to be lost (even though the container objects were singletons) and it always ended up requesting login again – GatoSoft Dec 20 '21 at 00:32
5

When you're navigating through the routerLink within Angular, the underlying JavaScript is determining what to serve to the browser. Meaning that when the URL address is changed via the Angular router, it picks up the change and serves the components accordingly.

When you update the URL manually and press enter, it is like going to a new web page. Meaning that the server will need to re-serve the base website, http://localhost:1234, and then the application will handle the route there after, /profile and serve the required component.

I've tried to explain it in a very simplistic way, for a more thorough explanation please check out the Angular docs

Wesley Coetzee
  • 4,768
  • 3
  • 27
  • 45
  • 1
    But why is the behavior different with AngularJS? With AngularJS it never happened to me! Is maybe for the ng-serve? – panagulis72 Jul 04 '18 at 08:28
  • 3
    It is due to the fact that there used to be a `#` in the URL. – Ankit Sharma Jul 04 '18 at 08:30
  • Damn you are right!! Adding: {useHash: true} it works! Now the choise is.. use hash or not? Maybe deleting the ProfileModule and including it in the CoreModule it works withouth refresh or problem is going to persist? – panagulis72 Jul 04 '18 at 08:54
  • You can remove the hash. You would have to configure your server to handle such requests in that case. – Ankit Sharma Jul 04 '18 at 09:07
  • I'm currently using ng-serve. Do you have an example or tutorial for the configuration that you are talking about? – panagulis72 Jul 04 '18 at 09:13
  • What server are you using to deploy the application? – Ankit Sharma Jul 04 '18 at 09:59
  • For local delevop: NGNIX; for production: Amazon Web Services (AWS) – panagulis72 Jul 04 '18 at 10:04
  • I have provided some details as an answer. Hope it helps and solves your problem. – Ankit Sharma Jul 04 '18 at 10:23
  • This thread was very helpful. It seems that `useHash: true` works if URLs are typed manually, but it doesn't work when the user refreshes the page in the Reload button of the browser. What could be a solution for this one? – chris May 02 '20 at 21:24
  • @chris page refresh is considered the same as closing and reopening the tab – Wesley Coetzee May 04 '20 at 08:32
  • @WesleyCoetzee so if I want to prevent the app from reloading entirely when the page is refreshed, that would be a configuration in the server to handle that? The reason is that I don't want my app.services to empty when refreshing – chris May 04 '20 at 13:23
  • @chris you're trying to stop default browser behaviour though? I'm not sure what you're keeping inside that service, but you could just fetch the data again, or redirect to the home page if the service is empty? – Wesley Coetzee May 04 '20 at 13:57
  • @WesleyCoetzee well I am keeping the user profile information. I have the access token in localStorage so I guess I can fetch that data again for the service if the page is refreshed. But is this ideal? I was thinking there was a way we could prevent the app from reloading if the page was refreshed. – chris May 04 '20 at 14:46
  • 1
    @chris - this is what local storage is used for :) – Wesley Coetzee May 05 '20 at 09:31
  • @WesleyCoetzee ok, tbh I wasn't sure if it was good practice to store user's profile (non-sensitive) data in localStorage. I guess it's totally normal, you just gave me the solution then, thanks :) – chris May 05 '20 at 11:40
4

When the routerLink is used, the JavaScript changes the URL , i.e., it is not regarded as reload of the web page.

However, when you hit an enter in the address bar, the page is reloaded, i.e., the content is again served from the server which serves the index.html (if you do not have any other HTML defined to be served in place of index) and hence the application reinitializes.

That is why all the components get reloaded.

As suggested by @Wesley, you can refer to the angular docs for more information.

https://angular.io/guide/router

You may explore the below mentioned blog for deployment purpose.

https://arjunphp.com/deploy-angular-app-production-nginx/

The main thing to notice here is try_files $uri $uri/ /index.html =404;. When an enter is hit on the address bar, NGINX first checks if the given URL maps to some file / route on the server. If it does not exist, which in our case localhost:8080/profile, does not as there is no such physical path. Hence, NGINX would serve the /index.html file, which in turn would fetch all JS files which would in turn handle the routing.

If you need to work with the API, you can use NGINX's reverse proxy mechanism to redirect for example, /api/ path to your corresponding server.

Ankit Sharma
  • 1,674
  • 8
  • 11
0

Routing is basically used to lazy load the application, one module at a time. Each route depends on the previous route and so on. So when you manually enter a url, the app will reload all the components in the route.

-1

I'm a bit late to answer this, but maybe this will also help someone.

You can create an .htaccess file that will transfer all requests to your index.html file

.htaccess

<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteBase /
  RewriteRule ^index\.html$ - [L]
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteRule . /index.html [L]
</IfModule>
Mudit Gulgulia
  • 1,131
  • 7
  • 21