Angular2 router issues when refreshing pages - .htaccess

I all,
I have a really common issue, but I didn't find the solution, and really need your help for this one.
I have an angular2 app on an apache server, and have issues with the router in lazy loaded modules.
I have a root module, and this is his router file:
import { NgModule } from '#angular/core';
import { RouterModule, Routes } from '#angular/router';
// App Components
import { AppComponent } from './app.component';
import { LoginComponent } from './auth/login.component';
const ROUTES: Routes = [
{ path: '', redirectTo: '/home', pathMatch: 'full' },
{ path: 'home',
loadChildren: 'dist/home/home.module.js#HomeModule'
}
{
path: 'childapp',
loadChildren: 'dist/childapp/childapp.module.js#ChildappModule'
},
{
path: 'login',
component: LoginComponent
},
{ path: '**', redirectTo: '/home'}
];
#NgModule({
imports: [ RouterModule.forRoot(ROUTES) ],
exports: [ RouterModule ]
})
export class RoutingModule {}
Here is on exemple of the routing of a child module:
import { NgModule } from '#angular/core';
import { RouterModule, Routes } from '#angular/router';
import { ModuleWithProviders } from "#angular/core";
import { ChildappComponent} from './childapp.component';
import { Sub1Component} from './sub1/Sub1.component';
import { Sub2Component} from './sub2/Sub2.component';
const routes = [
{
path: "",
component: ChildappComponent,
children: [
{path: "sub2",
component: Sub2Component},
{path: "",
component: Sub1Component},
]
},
];
#NgModule({
imports: [ RouterModule.forChild(routes) ],
exports: [ RouterModule ]
})
export class LocobookRoutingModule {}
When I click on links, everything is OK.
When I refresh "http://mywebsite.com/app/home", or "http://mywebsite.com/app/childapp", everything is OK.
But, when I try to refresh on "http://mywebsite.com/app/childapp/sub2", The page does not display.
If it helps, this is my .htacces file:
RewriteEngine on
# if a directory or a file exists, use it directly
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# otherwise forward it to index.php
RewriteRule . index.php
Thanks for your help on this.

I found a way to solve my problem.
Because I'm using Apache and PhP, I can easily specify an absolute in my index.php file:
<base href="<?= "http://".$_SERVER['HTTP_HOST'].str_replace("index.php", "", $_SERVER['SCRIPT_NAME']); ?>">
I hope it will help someone !

Related

Angular 12 sub routes 404 loosing context on refresh

I am having problem with angular 12 sub routes. I can navigate to the sub routes just fine but when I refresh the page I lose context. I am running it locally on the localhost:4200
here is the image of what I am getting in network tab and on the screen when I refresh
enter image description here
here is a link for source code: https://github.com/Stanmozolevskiy/Portfolio
Here is routing component:
import { SinglePortfolioComponent } from './portfolio/single-portfolio/single-portfolio.component';
import { HomeComponent } from './home/home.component';
import { NgModule } from '#angular/core';
import { RouterModule, Routes } from '#angular/router';
import { ContactComponent } from './contact/contact.component';
import { AboutComponent } from './about/about.component';
import { PortfolioComponent } from './portfolio/portfolio.component';
const routes: Routes = [
{path: '', component: HomeComponent},
{path: 'contact', component: ContactComponent},
{path: 'about', component: AboutComponent},
{path: 'about/portfolio', component: AboutComponent},
{path: 'portfolio', component: PortfolioComponent},
{path: 'portfolio/:query', component: SinglePortfolioComponent},
];
#NgModule({
imports: [RouterModule.forRoot(routes, {scrollPositionRestoration: 'enabled'})],
exports: [RouterModule]
})
export class AppRoutingModule { }
Here is app module:
import { AngularFireModule } from '#angular/fire';
import { AngularFireFunctionsModule } from '#angular/fire/functions';
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { HomeComponent } from './home/home.component';
import { FontAwesomeModule } from '#fortawesome/angular-fontawesome';
import { ContactComponent } from './contact/contact.component';
import { ReactiveFormsModule } from '#angular/forms';
import { AboutComponent } from './about/about.component';
import { GetintouchComponent } from './getintouch/getintouch.component';
import { PortfolioComponent } from './portfolio/portfolio.component';
import { SinglePortfolioComponent } from './portfolio/single-portfolio/single-portfolio.component';
import { HeaderComponent } from './common/header/header.component';
import { NgbModule } from '#ng-bootstrap/ng-bootstrap';
import { AsideComponent } from './common/aside/aside.component';
import { ParagraphComponent } from './common/paragraph/paragraph.component';
#NgModule({
declarations: [
AppComponent,
HomeComponent,
ContactComponent,
AboutComponent,
GetintouchComponent,
PortfolioComponent,
SinglePortfolioComponent,
HeaderComponent,
AsideComponent,
ParagraphComponent
],
imports: [
AppRoutingModule,
BrowserModule,
FontAwesomeModule,
ReactiveFormsModule ,
AngularFireFunctionsModule,
NgbModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
I will be happy to try any suggestions, thank you in advance!
Solution to this problem:
Change your webserver configurations to match your location strategy or use HashLocationStrategy as follow: imports: [RouterModule.forRoot(appRoutes, {scrollPositionRestoration: 'enabled', useHash: true})]
And please change all href attributes over your code base to routerLink directive as follow:
<a routerLink="/portfolio" class="btn btn-lg edit_hover_class custom-btn">
<fa-icon [icon]="faBriefcase"></fa-icon> My portfolio
</a>
I assume you're talking about the index.html fallback that doesn't work on the production like it works locally while in development.
You can fix your issue by looking at the docs here https://angular.io/guide/deployment#routed-apps-must-fallback-to-indexhtml.
Just know what is your online server and do the solution specific for it.

I can not directly access an url in Angular

I have a problem with a simple application. I already have it in production, but when I access a URL directly, I get an error:
In firefox:
In chrome:
But if I access localhost:8080, it is redirected to /home correctly:
I am using the following code:
In app.routes.ts
import { RouterModule, Routes } from '#angular/router';
import { HomeComponent } from './components/home/home.component';
import { AboutComponent } from './components/about/about.component';
import { HeroesComponent } from './components/heroes/heroes.component';
import { HeroeComponent } from './components/heroe/heroe.component';
import { BuscarComponent } from './components/buscar/buscar.component';
const ROUTES: Routes = [
{ path: 'home', component: HomeComponent },
{ path: 'about', component: AboutComponent },
{ path: 'heroes', component: HeroesComponent },
{ path: 'heroe/:id', component: HeroeComponent },
{ path: 'buscar/:palabra', component: BuscarComponent },
{ path: '**', pathMatch: 'full', redirectTo: 'home' }
];
export const APP_ROUTING = RouterModule.forRoot(ROUTES);
In app.module.ts
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { APP_ROUTING } from './app.routes';
import { HeroesService } from './servicios/heroes.service';
import { AppComponent } from './app.component';
import { NavbarComponent } from './components/shared/navbar/navbar.component';
import { HomeComponent } from './components/home/home.component';
import { AboutComponent } from './components/about/about.component';
import { HeroesComponent } from './components/heroes/heroes.component';
import { HeroeComponent } from './components/heroe/heroe.component';
import { BuscarComponent } from './components/buscar/buscar.component';
import { HeroeTarjetaComponent } from './components/heroe-tarjeta/heroe-tarjeta.component';
#NgModule({
declarations: [
AppComponent,
NavbarComponent,
HomeComponent,
AboutComponent,
HeroesComponent,
HeroeComponent,
BuscarComponent,
HeroeTarjetaComponent
],
imports: [
BrowserModule,
APP_ROUTING
],
providers: [
HeroesService
],
bootstrap: [AppComponent]
})
export class AppModule { }
I try to change { path: '**', pathMatch: 'full', redirectTo: 'home' } to { path: '', pathMatch: 'full', redirectTo: 'home' } or anything and nothing, not solve.
I tried the application with the NodeJS http-server module.

angular2 nested routing not working,no error reported,but blank page

Please help me check the code...There is no compilation error or else output in the cli after npm start .But the brower appears to be a blank page.
I have checked over and over again,but still can't find what's wrong.
PS:im a freshman in angular2...
app.module
#NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
AdminModule,
WaiterModule,
CookModule,
AppRoutingModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
app-routing.module
const appRoutes: Routes = [
{
path: "",
redirectTo: "/admin",
pathMatch:"full"
}
];
#NgModule({
imports: [
RouterModule.forRoot(appRoutes, { enableTracing: true })
],
exports: [RouterModule]
})
export class AppRoutingModule { }
app.component.html
<div style="text-align:center">
<h1>
Welcome to Angular2
</h1>
</div>
<router-outlet></router-outlet>
admin.module
#NgModule({
declarations: [
AdminComponent,
DishBoardComponent,
UserBoardComponent,
StatisticsBoardComponent,
AdminSiderBarComponent
],
imports: [
CommonModule,
AdminRoutingModule
]
})
export class AdminModule { }
admin-routing.module
const adminRoutes: Routes = [
{
path: "admin",
component: AdminComponent,
children: [
{ path: "", redirectTo: "/checkout",pathMatch:"full" },
{ path: "checkout", component: CheckoutBoardComponent },
{ path: "dish", component: DishBoardComponent },
{ path: "user", component: UserBoardComponent },
{ path: "statistics", component: StatisticsBoardComponent }
]
}
];
#NgModule({
imports: [
RouterModule.forChild(adminRoutes)
],
exports: [RouterModule]
})
export class AdminRoutingModule { }
admin.component.html
<p>
admin works!
</p>
<a routerLink="/checkout">Checkout</a>
<a routerLink="/user">User</a>
<a routerLink="/dish">Dish</a>
<a routerLink="/statistics">Statistics</a>
<router-outlet></router-outlet>
<br>
footer
It seems like you are not defining admin route and its children inside your app.routing.module.
You should get it to work with
app.module.ts:
No need to import other modules here. just import AppRoutingModule.
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
/** App Modules **/
import { AppRoutingModule } from './app.routing.module';
/** App Components**/
import { AppComponent } from './app.component';
#NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
AppRoutingModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
app.routing.module.ts:
Load admin.module routes and pass them to admin route.
import { NgModule } from '#angular/core';
import { RouterModule } from '#angular/router';
/** App Modules**/
import { AdminModule} from './admin/admin.module';
export function exportAdminModule() {
return AdminModule;
}
const appRoutes: Routes = [
{
path: 'admin',
loadChildren: exportAdminModule
},
{
path: '',
redirectTo: '/admin',
pathMatch: 'full'
},
{
path: '**',
redirectTo: '/admin'
}
];
#NgModule({
imports: [
RouterModule.forRoot(appRoutes, { enableTracing: true })
], exports: [RouterModule]
})
export class AppRoutingModule { }
admin.module.ts:
import { NgModule } from '#angular/core';
import { CommonModule } from '#angular/common';
// Import your components
/** App Routing **/
import { AdminRoutingModule} from './admin.routing.module';
#NgModule({
declarations: [
// your components
// your admin.component
],
imports: [
CommonModule,
AdminRoutingModule
]
})
export class AdminModule { }
admin.routing.module.ts:
Set up an empty path as base route ''.
import { NgModule } from '#angular/core';
import { RouterModule } from '#angular/router';
// Import your components
#NgModule({
imports: [
RouterModule.forChild([
{
path: '',
component: AdminComponent,
children: [
{ path: '', redirectTo: '/checkout', pathMatch: 'full' },
{ path: 'checkout', component: CheckoutBoardComponent },
. . .
]
}
])
], exports: [RouterModule]
})
export class AdminRoutingModule{ }
If you want to have more sub routes, for instance, nested router-outlet just replicate what I shown on app.module.routing with the export and the loadchildren.
I'm not quite sure that you want to achieve what you've shown on your app.routing.module. Are you sure you want to redirect everything to admin?
Something like:
#NgModule({
imports: [
RouterModule.forRoot([
{
path: 'login',
component: LoginPageComponent,
canActivate: [PreventLoggedInAccess]
},
{
path: 'admin',
loadChildren: exportAdminModule
},
{
path: '',
redirectTo: '/login',
pathMatch: 'full'
},
{
path: '**',
redirectTo: '/login'
}
], { useHash : true })
], exports: [RouterModule]
})
where PreventLoggedInAccess authguard prevents you to go to login if you are already logged in and
#NgModule({
imports: [
RouterModule.forChild([
{
path: '',
component: AdminComponent,
canActivateChild: [AuthGuardService],
children: [
. . .
]
}
])
], exports: [RouterModule]
})
with AuthGuardService allowing accessing to child routes only if you are logged in would make much more sense in my opinion.
Here you can read more about authguards.

No provider for Http Angular + Node.js API

I looked everywhere and could not find what I was doing wrong. I am using angular 2 to send a GET request to my node servers api and get information which it displays with databinding in my component called trade. The error occurs on the webbrowser when i try to view my angular app. Both my nodejs app and angular2 app are running on the same server.
Service:
https://hastebin.com/ileqekites.js
Component:
https://hastebin.com/agopopadus.cs
Do you have HttpModule imported into one of your Angular modules?
Here is one of mine as an example:
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { HttpModule } from '#angular/http'; // <- HERE
import { RouterModule } from '#angular/router';
import { AppComponent } from './app.component';
import { WelcomeComponent } from './home/welcome.component';
/* Feature Modules */
import { ProductModule } from './products/product.module';
#NgModule({
imports: [
BrowserModule,
HttpModule, // <- HERE
RouterModule.forRoot([
{ path: 'welcome', component: WelcomeComponent },
{ path: '', redirectTo: 'welcome', pathMatch: 'full' },
{ path: '**', redirectTo: 'welcome', pathMatch: 'full' }
]),
ProductModule
],
declarations: [
AppComponent,
WelcomeComponent
],
bootstrap: [ AppComponent ]
})
export class AppModule { }

angular 2 not finding route on refresh

I have develop a simple app following the angular 2 quickstart. It runs correctly in the lite-server.
Now I try to run the same application installed in apache under htdocs/foo but upon refresh, I am getting "Object not found".
baseHref
index.html:
<base href="/foo">
Routing
app.rounting.ts:
const appRoutes: Routes = [
{
path: 'sched',
component: ScheduleFormComponent
},
{
path: 'dashboard',
component: DashboardComponent
},
{
path: '',
redirectTo: '/home',
pathMatch: 'full'
},
{
path: 'home',
component: HomeComponent
},
{
path: 'sched-detail/:id',
component: ConsultationDetailComponent
}
];
I have also added the .htaccess using
<ifModule mod_rewrite.c>
Options +FollowSymLinks
IndexIgnore */*
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*) index.html
</ifModule>
But still no luck.
Is there something I am missing in the apache config?
I had the same problem, I solved it using the HashLocationStrategy
So in my app.module.ts
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { FormsModule } from '#angular/forms';
import { HttpModule } from '#angular/http';
import { HashLocationStrategy, LocationStrategy } from '#angular/common';
import { AppComponent } from './app.component';
import { MyComp1 } from './comp1/comp1.component';
import { MyComp2 } from './comp2/comp2.component';
import { routing } from './app.routing';
import 'rxjs/Rx';
#NgModule({
imports: [
BrowserModule,
FormsModule,
HttpModule,
routing
],
declarations: [
AppComponent,
MyComp1,
MyComp2
],
providers: [ {provide: LocationStrategy, useClass: HashLocationStrategy} ],
bootstrap: [AppComponent],
})
export class AppModule { }
Then my app.routing.ts looks like this
import { Routes, RouterModule } from '#angular/router';
import { MyComp1 } from './comp1/comp1.component';
import { MyComp2 } from './comp2/comp2.component';
const appRoutes: Routes = [
{
path: '',
redirectTo: 'mycomp1',
pathMatch: 'full'
},
{
path: 'mycomp1',
component: MyComp1
},
{
path: 'mycomp2/:id',
component: MyComp2
},
{ path: '**', redirectTo: 'mycomp1', }
];
export const routing = RouterModule.forRoot(appRoutes);
Before the HashLocationStrategy, I would have to go to the "home", aka MyComp1, route, refresh page, and then navigate to the one I wanted to refresh MyComp2, but now I can refresh from any one of my routes and it loads up fine.
Also I navigate to the routes using the routerLink
<a routerLink="/mycomp1" routerLinkActive="active">My Comp1</a>
<a [routerLink]="['mycomp2', myObj.id]" routerLinkActive="active">My Comp2</a>

Resources