Nginx Angular2 html5mode PathLocationStrategy - html

Given that Angular2 is a one page site, we need to redirect all url requests to index.html with Nginx.
Here is my Nginx server block:
server {
listen 8901;
server_name my_server_ip;
root /projects/my_site/dist;
location /.+\..+ { # files (assuming they always have a dot)
# use eg alias to serve some files here
}
location / { # url routed by client, client gives 404 for bad urls
try_files $uri /index.html;
}
}
This configuration globally works well. The navigation works, and I can access my pages directly by entering the url in the browser. But there are two problems:
When I enter a url in the browser then press enter to run (or if I simply refresh the page), it takes a very long time to load the page, near to 6 secondes. But if I remove the redirection from the Nginx server block, it takes less than one second.
But the navigation through the application (using the links) works as expected.
I have a link on my page (href) which point to the root (http://my_site.com/, it's the 'home' link). If I click it, it reload all the page. That's not the correct behavior in Angular2, it should just change the route to the home. This problem only occur on my server. If I run in my local machine, all works well, that's why I think that the problem comes from my Ngninx configuration.
What is the good configuration to use Nginx with Angular2?
EDIT:
I have started my project with the QUICKSTART projects from angular.io.
Here is my app.routing.ts file:
import { ModuleWithProviders } from '#angular/core';
import { Routes, RouterModule } from '#angular/router';
import { LoginComponent } from './login/index';
import { HomeComponent } from './home/index';
import { ProfileComponent, ProfileConsultComponent, ProfileHomeComponent, CoachsComponent, AthletesComponent } from './profile/index';
import { FeedPostComponent } from './feedpost/index';
import { AuthGuard } from './_guards/index';
const appRoutes: Routes = [
{ path: '', component: HomeComponent, canActivate: [AuthGuard] },
{ path: 'login', component: LoginComponent },
{ path: 'profile/:pk', component: ProfileConsultComponent },
{ path: 'home', component: ProfileHomeComponent, canActivate: [AuthGuard],
children: [
{ path: '', redirectTo: 'coachs', pathMatch: 'full' },
{ path: 'coachs', component: CoachsComponent },
{ path: 'athletes', component: AthletesComponent },
]
},
{ path: 'post/:pk', component: FeedPostComponent, canActivate: [AuthGuard] },
// otherwise redirect to home
{ path: '**', redirectTo: '' }
];
export const routing: ModuleWithProviders = RouterModule.forRoot(appRoutes);
And I've imported routing in the #NgModule import section on my app.module.ts file.

I have succeeded to setup correctly nginx to work as expected with Angular 2. Here is my server block:
server {
listen 80;
server_name my_server_name;
root /projects/angular2/myproject/dist;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
}

You should not add a redirect to the nginx but change the routing of your application server to serve the page containing your application for paths that are valid clientside.
Its nicely explained here for an express application. ( start a min 2:00)
EDIT
https://www.youtube.com/watch?v=ANfplcxnl78&index=2&list=PLOa5YIicjJ-VA38pChXHhq8jY2U8iYynr
for nginx it should be something like
location ~ ^/([^/]+)/([^/?]+)$ {
/index.html;
}
The try_files will check for the file speciefied in the path and will not work
You would also need to remove the first specification

Related

Does the routing paths order matter in angular?

I'm trying to make a router for one of my components, but it is not working as expected.
Initially it was working fine, but I had to add another route to decide which mat-tab would be open when redirecting. I added the second route like that, but for some reason the third one stopped working even though the first two were working fine.
import { Routes } from '#angular/router';
import { ActionComponent } from './action.component';
import { ActionResolver } from './action.resolver';
import { ACTION_RESULT_ROUTES } from './result/action-result.routes';
export const ACTION_ROUTES: Routes = [
{ path: ':id', component: ActionComponent, resolve: { action: ActionResolver } },
{ path: ':id/:tab', component: ActionComponent, resolve: { action: ActionResolver } },
{
path: 'action-result',
children: ACTION_RESULT_ROUTES,
},
];
I got a pretty large error when trying the third route, but it starts like this:
ERROR Error: Uncaught (in promise): TypeError: You provided 'null' where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.
Just in case, I tried to reorder it and all three were working fine when I did it like this:
export const ACTION_ROUTES: Routes = [
{ path: ':id', component: ActionComponent, resolve: { action: ActionResolver } },
{
path: 'action-result',
children: ACTION_RESULT_ROUTES,
},
{ path: ':id/:tab', component: ActionComponent, resolve: { action: ActionResolver } },
];
Can anyone tell me why it works like that?
Edit: Added the ACTION_RESULT_ROUTES for clarification
export const ACTION_RESULT_ROUTES: Routes = [
{ path: ':id', component: ActionResultComponent, resolve: { result: ActionResultResolver } },
];
According to Angular:
"The order of routes is important because the Router uses a
first-match wins strategy when matching routes, so more specific
routes should be placed above less specific routes."
It is recommended to have static routes first, therefore your action-result path should go first, followed by the :id/:tab path then :id path last. If you have a wildcard route, it should always be the last route in your array.
The reason behind this logic is that if you had the :id path above the action-result path, angular would use the word 'action-result' as the id in the :id path.
Similarly if you had the :id path above the :id/:tab path, angular would use the words id/tab as the id in the :id path.
So, a rule of thumb is to always put your static routes first, then your dynamic routes from the most specific to the least specific followed by your wildcard route at the end.
E. G.
PATH1
PATH2
PATH3/:USER/:ROLE/:PAGE
PATH4/:SITE/:ID
PATH5:/ID
Wildcard route (*)

angular "Unable to extract routes" when using ng run prerender and generated routes

I am trying to generate routes from json file as I have generic view, which based on json data will create separate view with unique slug also based on this json file there are also sitemaps generated, so its used for two purposes.
generic_pages.json
{
INDUSTRIES: [
{
template: {
title: 'page title',
bannerPath: 'assets/banners/bann.jpg'
},
path: 'industry-name',
...
},
{
template: {
title: 'other page title',
bannerPath: 'assets/banners/other-bann.jpg'
},
path: 'other-industry'
},
....
]
}
and now I am importing this json to routing module, and mapping those routes and pass template to data in following way:
app.routing.module.ts
import * as genericPages from './generic_pages.json';
const industriesPages = genericPages.INDUSTRIES_PAGES.map(page => ({
path: page.path,
loadChildren: () => import('./components/pages/industry-page/industry-page.module').then(m => m.IndustryPageModule),
data: {
title: page.meta.title ? page.meta.title : '',
description: page.meta.description ? page.meta.description : '',
industryTemplate: page.template
}
}));
const routes: Routes = [ ... , ...industriesPages}
#NgModule({
imports: [RouterModule.forRoot(routes, {
initialNavigation: 'enabled',
anchorScrolling: 'enabled',
onSameUrlNavigation: 'reload',
scrollPositionRestoration: 'enabled'
})],
exports: [RouterModule]
})
export class AppRoutingModule { }
and those routes are working properly, when i run ng serve or ng run app:serve-ssr, they are seen and I can access them by URL directly.
The prob exists only when I deploy app, and there is ng run app:prerender, which throws error Unable to extract routes, and on server those routes aren't seen when i want to enter them directly by pasting url (such as domain.com/industry-name) to browser, but when I enter domain.com and click links I can access those routes, and also I noticed when those routes are hardcoded in const routes: Routes = [...] everything is ok, error only occurs when I am mapping and then concatenating to const routes, and also noticed when i erase loadChildren prop from mapping it stops throwing this error.

Angular 7 routing ignore path

I have an Angular 7 application, running .Net Core on the back end.
I have the following routes defined:
const routes: Routes = [
{ path: 'home', component: HomeComponent },
{ path: 'login', component: LoginComponent },
{ path: 'about', component: AboutComponent },
{ path: '**', redirectTo: 'home' }
];
In Visual Studio 2019, this is running at https://localhost:44358.
All works as expected.
But now I want to get metadata for a SAML implementation using sustainsys.saml2.aspnetcore2.
To get the metadata file, I try to enter https://localhost:44358/Saml2/ in my browser.
As expected, because the path does not match anything defined, the default route takes over and I am routed to the home page.
I removed the final path, so I no longer had any default routing for unmatched paths, and then it worked fine to get the metadata.
My question is: Is there any way to redirect to 'home' for all unmatched paths except some configured path (or paths), which would just be ignored as if the default route were not present?
Rather add a path to your base-href in index.html (e.g. <base href="/app/"/>) so that the Angular Router won't pick up paths on your root, then you'll be able to keep your wildcard redirect as is and /Saml2/ won't be intercepted.
Of course, if the app is already in production and you need to preserve URLs, you might not be in a position to make this kind of change.

While executing my project in angular6 its executing only index.html page only, what are the reasons?

I had created one project for login form, here am attaching screenshot of program,
while am executing my project it is showing only index page and waited for some time but still showing only index page, here am attaching output screenshot,
If you want to display a login page as a default page when user serves the application then you have to configure your app.module.ts to handle these type of URL. So the changes that you required is as:
In app.module.ts:
Import RouterModule from angular/router:
import { RouterModule } from '#angular/router';
and in imports Array add
RouterModule.forRoot([
{ path: '', redirectTo: '/login', pathMatch: 'full' },
{ path: 'login', component: LoginComponent }
])
and in app.component.html:
<router-outlet></router-outlet>
That’s because when we run ng-serve to start up our server it creates JavaScript bundles and automatically adds the right imports into our index.html.
In order for your app.component.html to show in localhost:4200, add <router-outlet></router-outlet? to your index.html.

How to navigate to other page in angular 6?

Im trying to redirect my page from login to another page. Im following this code.
My login component ts file:
import { Router } from '#angular/router';
constructor(private router: Router) {
}
funLogin(mobilenumber){
this.router.navigateByUrl('registration');
}
In my html Im calling this function in a submit btn,
<button class="common-btn btn" (click)="funLogin(mobileNo.value)">Submit</button>
In my app.login.routing file,
export const loginRouting: Routes = [
{
path: '', component: DashboardRootComponent, canActivateChild: [],
children: [
{ path: '', component: DashboardComponent, pathMatch: 'full' },
{ path: 'home', component: HomeComponent },
{ path: 'registration', component: RegistrationComponent },
]
}
]
I have tried with "this.router.navigate" & referredlot of links. But it didnt work. Can anyone please tell me where Im going wrong or if you could give me a workingh sample it would be better.
#sasi.. try like this,
<a routerLink="/registration"><button class="btn btn-success" > Submit </button></a>
Update :
In order to use the routing in your application, you must register the components which allows the angular router to render the view.
We need register our components in App Module or any Feature Module of it (your current working module) in order to route to specific component view.
We can register components in two ways
.forRoot(appRoutes) for app level component registration like
featuteModules(ex. UserManagement) and components which you want register at root level.
.forChild(featureRoutes) for feature modules child components(Ex. UserDelete, UserUpdate).
you can register something like below,
const appRoutes: Routes = [
{ path: 'user', loadChildren: './user/user.module#UserModule' },
{ path: 'heroes', component: HeroListComponent },
];
#NgModule({
imports: [
BrowserModule,
FormsModule,
RouterModule.forRoot(
appRoutes
)
],
P.S : In order to navigate from one component to another, you must include the RouterModule in corresponding Module Imports array from #angular/router package.
You can navigate one to another page in Angular in Two ways. (both are same at wrapper level but the implementation from our side bit diff so.)
routerLink directive
routerLink directive gives you absolute path match like navigateByUrl() of Router class.
<a [routerLink]=['/registration']><button class="btn btn-success" > Submit </button></a>
If you use dynamic values to generate the link, you can pass an array of path segments, followed by the params for each segment.
For instance routerLink=['/team', teamId, 'user', userName, {details: true}] means that we want to generate a link to /team/11/user/bob;details=true.
There are some useful points to be remembered when we are using routerLink.
If the first segment begins with /, the router will look up the route
from the root of the app.
If the first segment begins with ./, or doesn't begin with a slash,
the router will instead look in the children of the current activated
route.
And if the first segment begins with ../, the router will go up one
level.
for more info have look here.. routerLink
Router class
We need inject Router class into the component in order to use it's methods.
There more than two methods to navigate like navigate() , navigateByUrl(), and some other.. but we will mostly use these two.
navigate() :
Navigate based on the provided array of commands and a starting point. If no starting route is provided, the navigation is absolute.
this.route.navigate(['/team/113/user/ganesh']);
navigate() command will append the latest string is append to existing URL. We can also parse the queryParams from this method like below,
this.router.navigate(['/team/'], {
queryParams: { userId: this.userId, userName: this.userName }
});
You can get the these values with ActivatedRoute in navigated Component. you can check here more about paramMap, snapshot(no-observable alternative).
navigateByUrl()
Navigate based on the provided URL, which must be absolute.
this.route.navigateByUrl(['/team/113/user/ganesh']);
navigateByUrl() is similar to changing the location bar directly–we are providing the whole new URL.
I am using angular 7 and I solved it in this way into my project.
1.First We need to implement this Modules to our app.module.ts file
import { AppRoutingModule} from './app-routing.module';
import { BrowserModule } from '#angular/platform-browser';
import { FormsModule } from '#angular/forms';
#NgModule({
imports: [
BrowserModule,
AppRoutingModule,
FormsModule,
],
})
2.Then Open your.component.html file and then fire a method for navigate where you want to go
<button class="btn btn-primary" (click)="gotoHome()">Home</button>
3.Then Go your.component.ts file for where you want to navigate. And add this code there.
import { Router } from '#angular/router';
export class YourComponentClassName implements OnInit {
constructor(private router: Router) {}
gotoHome(){
this.router.navigate(['/home']); // define your component where you want to go
}
}
4.And lastly want to say be careful to look after your app-routing.module.ts
where you must have that component path where you want to navigate otherwise it will give you error. For my case.
const routes: Routes = [
{ path:'', component:LoginComponent},
{ path: 'home', component:HomeComponent }, // you must add your component here
{ path: '**', component:PageNotFoundComponent }
];
Thanks I think, I share all of the case for this routing section. Happy Coding !!!
navigateByUrl expects an absolute path, so a leading / might take you to the right page
You could also use navigate and don't need the leading / but the syntax is slightly different as it expects an array for the path
https://angular.io/api/router/Router#navigateByUrl
<a class="nav-link mt-1" [routerLink]="['/login']"><i class="fa fa-sign-in"></i> Login</a>