Angular 4 with MVC Routing refreshes page - asp.net-mvc

I have an angular 4 app with dotnet core 2 and MVC. My home page loads fine, but when I click on a link that should cause client-side routing, I get routed to the page and then it refreshes. After the refresh I am on the right page but I am trying to figure out how to stop the server from refreshing the page (presumably returning a 404) and then the client side showing the site correctly.
Here is my routing config in startup.cs:
app.UseStaticFiles();
app.UseMvc(routes =>
{
routes.MapSpaFallbackRoute(
name: "spa-fallback",
defaults: new { controller = "Home", action = "Index" });
});
and here is a sample of 2 routing configs in my angular app:
app module:
#NgModule({
declarations: [
AppComponent,
ExperienceComponent
],
imports: [
BrowserModule,
FormsModule,
HttpModule,
AngularFontAwesomeModule,
PaymentsModule,
RouterModule.forRoot([
{ path: "home", component: ExperienceComponent },
{ path: "", redirectTo: "/home", pathMatch: "full" },
{ path: "**", redirectTo: "/home" }
]),
],
providers: [],
bootstrap: [AppComponent]
})
and Payments module:
#NgModule({
providers: [],
imports: [
RouterModule.forChild([
{ path: "payments", component: LandingComponent }
])
],
declarations: [
LandingComponent
]
})
export class PaymentsModule {
}
When I click on a link that takes me to /payments, I see "loading...." show up for a second and then LandingComponent's HTML is shown.

Try adding this to the request pipeline in Startup.cs under the Configure method:
app.Use(async (context, next) =>
{
await next();
if (context.Response.StatusCode == 404 && !Path.HasExtension(context.Request.Path.Value))
{
context.Request.Path = "/home/index";
await next();
}
});
Basically you're telling ASP.NET that any 404 error should be treated as though the request is staying on /home/index (or wherever your SPA code is - in my case it's usually just in /index.html)

Related

Routing problem when application is starting Ionic 4

We are developing an application with Ionic 4 with the framework Angular.
We have an issue when we log to the application.
You can see the error on the picture:
My code is here:
import { NgModule } from '#angular/core';
import { RouterModule, Routes } from '#angular/router';
import { TabsPage } from './tabs.page';
const routes: Routes = [
{
path: 'tabs',
component: TabsPage,
children: [
{
path: 'tab1',
children: [
{
path: '',
loadChildren: '../tab1/tab1.module#Tab1PageModule'
}
]
},
{
path: 'tab2',
children: [
{
path: '',
loadChildren: '../tab2/tab2.module#Tab2PageModule'
}
]
},
{
path: 'tab3',
children: [
{
path: '',
loadChildren: '../tab3/tab3.module#Tab3PageModule'
}
]
},
{
path: '',
redirectTo: '/tabs/tab2',
pathMatch: 'full'
}
]
},
{
path: '',
redirectTo: '/tabs/tabs/tab2',
pathMatch: 'full'
}
];
#NgModule({
imports: [
RouterModule.forChild(routes)
],
exports: [RouterModule]
})
export class TabsPageRoutingModule {}
I don't believe in magic but when i delete one dot on the loadchildren exemple :
../tab3/tab3.module#Tab3PageModule -> ./tab3/tab3.module#Tab3PageModule
I do it on all the loadchildreds I'm saving the page I try to log in, same problem
and after I reput the dot like this
./tab3/tab3.module#Tab3PageModule -> ../tab3/tab3.module#Tab3PageModule
I'm saving, I try to log in again and it works fine. With this problem, we can't compile on ios.
I think you have to resolve relative paths for your tabs. Use augury chrome to check and resolve your routing. Also try to simplify your routing.
{
path: 'tab2',
loadChildren: () => import('./tab2/tab2.module').then(m => m.Tab2PageModule)
},

Preloading Strategy issue for forChild routes

My application is a bit large in size. It contains many feature modules and most are lazily loaded. I want to preload a lazily loaded module, which is included in forChild routes.
For this, I have referred to Angular documentation and followed their steps. I have provided a custom preloading strategy service mentioned below.
This is my custom preloading strategy file:
#Injectable()
export class CustomPreloadingWithDelayStrategy implements PreloadingStrategy {
preload(route: Route, load: () => Observable<any>): Observable<any> {
if (route.data && route.data['preload']) {
return load();
} else {
return Observable.of(null);
}
}
}
app-routing file,
const routes: Routes =
[
XXX,
{
path: '',
data: {
base: true
},
component: MyComp,
children: [
{
path: 'page1/:id',
loadChildren: 'XXXXXXX'
},
{
path: 'page2',
loadChildren: 'XXXXXXXX'
},
{
path: 'page3',
loadChildren: 'app/feature-modules/folder1/my-folder1-module#Folder1Module'
}];
#NgModule({
imports: [RouterModule.forRoot(routes, {useHash: true, preloadingStrategy: CustomPreloadingWithDelayStrategy})],
exports: [RouterModule],
entryComponents: [ ]
})
export class AppRoutingModule {}
My Folder1Module's routing file:
const routes: Routes = [{
path: 'sub-page1/:data1/:data2',
loadChildren: 'app/feature-modules/sub-pages/pages/sub-page1.module#SubPage1Module'
}, {
path: 'sub-page2/:data1',
loadChildren: 'app/feature-modules/sub-pages/pages/sub-page2.module#SubPage2Module',
data: {preload: true}
}];
#NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class Folder1RoutingModule {
}
So when I open this route /page3/sub-page1/data1/data2, SubPage2Module is to be preloaded. But that is not happening.
I have spent nearly 2 hours to understand why the module is not pre-loaded even when I was doing everything right.
The problem lies with children, any route that is defined and further distributed with children is considered as a normal route even if you've defined your modules within the children with the help of loadChildren. The preloadingStrategy just takes modules to preload and not path/routes. The moment you've defined your routes under children it considers it as normal route and moves on to scan other routes that are provided with loadChildren. Following is the interpretation of Angular with your routes:
const routes: Routes =
[
XXX, // Normal path
{
path: '',
data: {
base: true
},
component: MyComp,
children: [ // Normal path (no module) as children is used, move on
{
path: 'page1/:id',
loadChildren: 'XXXXXXX'
},
{
path: 'page2',
loadChildren: 'XXXXXXXX'
},
{
path: 'page3',
loadChildren: 'app/feature-modules/folder1/my-folder1-module#Folder1Module'
},
],
},
{ path: 'abc', loadChildren: '../path/to/module#AbcModule', data: { preload: true }} // Module found, preload it!
];
If you debug closely in your custom CustomPreloadingWithDelayStrategy then you will observe that your route /page3/sub-page1/data1/data2 can't even make up to the route parameter of preload() method because preloading is all about loading module and not about loading routes. However, our route abc does make an appearance! Hope it helps :)

Angular routing redirect to that same page all time

I have problem with routing in my application. I use Angular2+ and WebApi2. I created Angular from quickstart project and I added it to my WebApi solution. After configurating it, I launched first time app allthing work fine. Problems appear after I added routing. When I try to navigate to link included in routing table, the browser redirect me all time to one component. I searched how to deal with it but I didn't find anything. Below I present codes and file names:
RouteConfig.cs
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{*url}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
Share _Layout.cshtml
<script src="/node_modules/core-js/client/shim.min.js"></script>
<script src="/node_modules/zone.js/dist/zone.js"></script>
<script src="/node_modules/systemjs/dist/system.src.js"></script>
<script src="~/src/systemjs.config.js"></script>
<script>
System.import('./src/main.js').catch(function (err) { console.error(err); });
</script>
system.config.js
packages: {
app: {
defaultExtension: 'js',
meta: {
'./*.js': {
loader: '/src/systemjs-angular-loader.js'
}
}
},
rxjs: {
defaultExtension: 'js'
}
}
app.module.ts
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { RouterModule, Routes } from '#angular/router';
import { AppComponent } from './app.component';
import { HomePage } from './HomePage.component';
import { Test } from './Test.component';
import { HttpModule } from '#angular/http';
const appRoutes: Routes = [
{ path: '', redirectTo: 'home', pathMatch: 'full' },
{ path: 'home', component: HomePage },
{ path: 'test', component: Test },
{ path: '**', component: HomePage }
];
#NgModule({
declarations: [
AppComponent, HomePage, Test
],
imports: [
BrowserModule,
HttpModule,
RouterModule.forRoot(appRoutes)
],
providers: [],
bootstrap: [HomePage]
})
export class AppModule { }
Index.cshtml
<home-page></home-page>
Answer: all problems are caused by #RenderBody(). When I moved <home-page></home-page> under #RenderBody() all is working fine.

Connect Angular routing with MVC routing

In my new project in WebApi2 I use Angular2 framework. After configuring and adding angular I tried to call first compnent. And there is my question. How to connect angular routing with webapi2? I add new class where I add routing:
I call <home-page> in MVC controller view Index.cshtml
app.routing.ts
const appRoutes: Routes = [
{ path: 'home', component: HomePage },
{ path: 'test', component: AppComponent}
];
app.component.ts
#Component({
selector: 'my-app',
templateUrl: './app.template.html',
})
HomePage.component.ts
#Component({
selector: 'home-page',
templateUrl: './HomePage.template.html',
providers: [GetContent]
})
system.config.js
paths: {
// paths serve as alias
'npm:': 'node_modules/'
},
// map tells the System loader where to look for things
map: {
// our app is within the Angular folder
'app': 'Angular',
// angular bundles ...
}
meta: {
'./*.js': {
loader: '/systemjs-angular-loader.js'
}
}
shared _Layout.cshtml
<script src="/node_modules/core-js/client/shim.min.js"></script>
<script src="/node_modules/zone.js/dist/zone.js"></script>
<script src="/node_modules/systemjs/dist/system.src.js"></script>
<script src="/systemjs.config.js"></script>
<script>
System.import('Angular/main.js').catch(function (err) { console.error(err); });
</script>
I included it to app.module.ts to imports section. When I launch application I see information from my HomePage component but when I add route path /test, it redirects me to HomePage component. Where have I made a mistake?
Can you try edit your app.module into this:
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { RouterModule, Routes } from '#angular/router';
import { AppComponent } from './app.component';
import { HomePageComponent } from './home-page.component';
const appRoutes: Routes = [
{path: '', redirectTo: 'home', pathMatch: 'full'},
{ path: 'home', component: HomePageComponent },
{ path: 'test', component: AppComponent}
{path: '**', component: NotFoundComponent}
];
#NgModule({
declarations: [
AppComponent,HomePageComponent
],
imports: [
BrowserModule,
RouterModule.forRoot(appRoutes)
],
providers : [],
bootstrap: [AppComponent]
})
export class AppModule { }
I resolved problem. I called <home-page> in Index.cshtml and that view was rendered from _Layout.cshtml. When I moved called component to _Layout.cshtml all things go correct. Thanks for help!

Modify URL in asp.net zero

I have different tenants name and a login page whose path is localhost:4200/account/login but before that i have localhost:4200/account/workspace page where i will enter my tenantName in a textbox and the particular tenantId will be in the cookies. Now i want my next login page url to be like this
localhost:4200/tenantName/account/login and even after login i want the tenantName exactly there throughout the whole session. I am new to this and completely stuck here for 2 days. How can i modify my url here? This is problem is almost similar to this problem here.
https://forums.asp.net/t/2127416.aspx? How+to+modify+login+url+when+using+asp+net+identity
The difference is that i have to make changes in my front-end and not in the backend and its asp.net zero not asp.net core. Here is the code for my root-routing module file.
import { NgModule } from '#angular/core';
import { Routes, RouterModule } from '#angular/router';
const routes: Routes = [
{ path: '', redirectTo: '/app/home', pathMatch: 'full' },
{
path: 'account',
loadChildren: 'account/account.module#AccountModule', //Lazy load account module
data: { preload: true }
},
{
path: 'app',
loadChildren: 'app/app.module#AppModule', //Lazy load account module
data: { preload: true }
}
];
#NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
providers: []
})
export class RootRoutingModule { }

Resources