I have a project with file structure
app/
(all the files that get automatically built)
app-routing.module.ts
components/
layout/
top/
side/
banner/
pages/
home/
prehistory/
prehuman/
australopithecine/
homininia/
earlyHuman/
outOfAfrica/
agriculture/
ancient/
(several directories like in prehistory)
post-classical/
(several directories like in prehistory)
Each directory under pages/ was built in the CLI with ng g c ___ so that it has all the usual files. I'm trying to build the router so that it reflects the directory structure with child routers, so I have in app-routing.module.ts the following code. Note that since I'm at the early stages I haven't fully written out all the children and their sub-children, I just wanted to get a small part of it built and tested before building out the rest.
app-routing.module.ts
import { NgModule } from '#angular/core';
import { Routes, RouterModule } from '#angular/router';
import { HomeComponent } from './components/pages/home/home.component';
import { PrehistoryComponent } from './components/pages/prehistory/prehistory.component';
export const routes: Routes = [
{path:'', children: [
{path:'prehistory', component:PrehistoryComponent},
{path:'', component:HomeComponent},
]}
];
#NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule {
}
In my AppComponent I used header and other tags to control CSS styles, but the important part is that there's a portion of the screen reserved for the header, for the side, and then the content which is the part that changes based on the address.
app.component.html
<header>
<app-top></app-top>
</header>
<aside>
<app-side></app-side>
</aside>
<content>
<router-outlet></router-outlet>
</content>
And the links are in the TopComponent.
top.component.html
<div><app-banner></app-banner></div>
<div id="breadcrumb">
<nav>
<a [routerLink]="['']" routerLinkActive="active">Home</a>
<a (mouseover)="onHover()" [routerLink]="['prehistory']" routerLinkActive="active">Prehistory</a>
</nav>
</div>
top.component.ts
import { Component, OnInit } from '#angular/core';
import { ActivatedRoute } from '#angular/router';
#Component({
selector: 'app-top',
templateUrl: './top.component.html',
styleUrls: ['./top.component.css'],
})
export class TopComponent implements OnInit {
constructor(private route: ActivatedRoute) {
}
onHover = function() {
console.log(this.route.url._value[0]);
}
ngOnInit() {
}
}
When my browser navigates to /prehistory the page loads correctly but the console prints out "" indicating the root route URL. And when I've also tried logging to console the parent directory, it prints null, confirming that the activated route is representing the root directory even though the page has navigated away from it.
home.component.html
<p>
home works!
</p>
<router-outlet></router-outlet>
prehistory.component.html
<p>
prehistory works!
</p>
<router-outlet></router-outlet>
Using .forChild instead of .forRoot seems to break the page. I am wondering if maybe I need to use a service to pass information around? Like maybe I need a service to somehow collect the current route from the content tag and pass that over to the TopComponent? But I'm not sure how I would get a service that collects the route from the content tag.
I think the most important is to activate this property: useHash: true and then manage the path correctly with the name of each component.
Try changing to this code:
export const routes: Routes = [
{ path: 'home', component: HomeComponent},
{path:'children', component: [
{path:'prehistory', component:PrehistoryComponent},
{path:'**', component:HomeComponent},
]},
{ path: '**', pathMatch: 'full', redirectTo: 'home'}
];
#NgModule({
imports: [RouterModule.forRoot(routes, { useHash: true })],
exports: [RouterModule]
})
Related
My root component is loading twice even though I have a separate component for my homepage. I have tried to use different things, such as pathMatch, separate component, etc, but no luck. When I go to /dashboard, it works just fine, but when it loads the page initially (root page), the navbar is loaded twice. I want to avoid that.+
My code looks like this:
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { NavbarComponent } from './navbar/navbar.component';
import { NgbModule } from '#ng-bootstrap/ng-bootstrap';
import { RouterModule, Routes } from '#angular/router';
import { RootComponent } from './root/root.component';
import { FeatureDashboardComponent } from '#angular/dashboard';
import { FeatureHomepageComponent } from '#angular/homepage';
const routes: Routes = [
{
path: '',
component: RootComponent,
pathMatch: 'full',
children: [
{
path: '',
component: FeatureHomepageComponent
}
]
},
{
path: 'dashboard',
component: FeatureDashboardComponent
},
{
path: '**',
redirectTo: ''
}
];
#NgModule({
declarations: [
NavbarComponent,
RootComponent
],
imports: [
BrowserModule,
NgbModule,
RouterModule.forRoot(routes)],
providers: [],
bootstrap: [RootComponent],
})
export class AppModule {}
And my HTML for RootComponent is:
<angular-navbar></angular-navbar>
<div class="layout">
<router-outlet></router-outlet>
</div>
And navbar is:
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container-fluid">
<a class="navbar-brand">My App</a>
</div>
</nav>
Example in inspect
I think the problem might be that you have the route '' loading the RootComponent and the children route tries to load FeatureHomepageComponent but is also '', which can't be effectively resolved by the router.
Try giving the children route a path that is not empty, like this:
...
{
path: '',
component: RootComponent,
pathMatch: 'full',
children: [
{
path: 'home',
component: FeatureHomepageComponent
}
]
},
...
And play with the redirect at the end, so when your application loads, it should navigate to (for example) localhost:4200/home
I think the problem is with this code:
path: '',
component: RootComponent,
you most likely do NOT want to have your RootComponent here as it would allow the RootComponent to appear within your
<router-outlet>
and could explain why you have 2 of them.
<router-outlet>
should only route to CHILDREN of your RootComponent.
In other words, no route (in your routing config) should render your RootComponent it's already being rendered. The routes there should only render what you want to display WITHIN your router-outlet, aka CHILDREN of your RootComponent
For the solution I think you just have to make this:
path: '',
component: FeatureHomepageComponent
the first path in your config (delete the RootComponet part and the children:[] part)
Instead of calling the router-outlet try to call to the exact component name
This means you have either of two: another <router-outlet></router-outlet> instance or you are instantiating the <angular-navbar></angular-navbar> in another template other than the one you show here. pathMatch has nothing to do here because the <angular-navbar></angular-navbar> component is route agnostic, meaning it is a layout component.
This question already asked but it doesn't work for me, am new in Angular 9.
I have admin and catelog folders in my Angular 9 project. For admin folder I try to load all admin-components, and catelog folder I try to load catelog-components.
CSS, js and images not loading in catelog check below image
app-routing.module.ts
import { NgModule } from '#angular/core';
import { Routes, RouterModule } from '#angular/router';
import { AuthGuard } from './admin/helper/auth.guard';
import { LoginComponent } from './admin/pages/login/login.component';
const adminModule = () => import('./admin/pages/pages.module').then(x => x.PagesModule);
const catelogPageModule = () => import('./catelog/pages/catelog.module').then(x => x.CatelogModule);
const routes: Routes = [
// catalog url
{ path: '', loadChildren:catelogPageModule },
//admin url
{ path: 'login', component: LoginComponent },
{ path: 'admin', loadChildren:adminModule, canActivate: [AuthGuard] },
// otherwise redirect to home
// { path: '**', redirectTo: 'home' }
];
#NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
catelog.module.ts
import { NgModule } from '#angular/core';
import { CommonModule } from '#angular/common';
import { FormsModule, ReactiveFormsModule } from '#angular/forms';
import { CatelogRoutingModule } from './catelog-routing.module';
import { HomeComponent } from './home/home.component';
import { CommonComponent } from './common/common.component';
import { AboutUsComponent } from './about-us/about-us.component';
#NgModule({
declarations: [
CommonComponent,
HomeComponent,
AboutUsComponent,
],
imports: [
CommonModule,
ReactiveFormsModule,
CatelogRoutingModule,
FormsModule
]
})
export class CatelogModule { }
catelog-routing.module.ts
import { NgModule } from '#angular/core';
import { Routes, RouterModule } from '#angular/router';
import { AboutUsComponent } from './about-us/about-us.component';
import { CommonComponent } from './common/common.component';
import { HomeComponent } from './home/home.component';
const routes: Routes = [
{
path: '', component:CommonComponent,
children:[
{ path: 'home', component: HomeComponent },
{ path: 'about-us', component: AboutUsComponent },
]
}
];
#NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class CatelogRoutingModule { }
app\catelog\pages\common\common.component.html
<!doctype html>
<html class="no-js" lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<title>Title</title>
<!-- CSS here -->
<link href="/assets/catelog/assets/css/bootstrap.min.css">
</head>
<body>
<!-- header-area -->
<header>
<!-- menu-area -->
</header>
<!-- header-area-end -->
<!-- Main content -->
<router-outlet></router-outlet>
<!-- Main content -->
<!-- footer-area -->
<footer class="dark-bg pt-55 pb-80">
copyrights
</footer>
<!-- footer-area-end -->
<!-- JS here -->
<script src="/assets/catelog/assets/js/vendor/jquery-3.5.0.min.js"></script>
<script src="/assets/catelog/assets/js/main.js"></script>
</body>
</html>
My folder structure:
Admin folder CSS, js and images working properly, but catelog folder CSS, js and images not loading.
Please help me to short out this issue.
You shouldn't be putting whole <html><body>...</body> inside your component template. The common.component.html should look like:
<header>someHeader</header>
<router-outlet></router-outlet>
<footer>some data</footer>
So without <html>, <body>, <srcipts> etc.
If you need to load bootstrap.css - you can do it in global styles.scss file, and for loading js files you can use angular.json ( there is a place to place additional js over there )
You should follow what Panda already suggested but I will modify little bit the answer based on the css issue you are facing
Structure your project routes as per following
Main page
<html>
<body>
<header-comp/>
<app-comp></app-comp>
<footer-comp/>
</body>
</body>
At app component html
<router-outlet/>
At app component module
Add app component, add routes to two lazy loading modules home and admin plus extra route entry that redirects default route to home module
Now since home and admin are two modules each will have its own home page , that home page is is the default entry of the home/admin routing module with sub children routes to other module pages and its html looks like that
<router-outlet></router-outlet>
In the module home page component definition add the desired boatstrap css version
#component({
selector:'home-app-comp',
html:'<router-outlet/>',
styleUrl:[path to css file]
})
The whole idea is based on having some sort of nested routes where each module main page loads desired bootstrap version and acts as a parent container for the rest of the module pages
I was working on a big project of mine in angular, discovered feature modules and routing modules, then tried to implement that in order to better organize the project. When I did this, the app became very disfunctional. Since then, i made this test project to try to implement routing between feature modules, on a smaller, more managable scale.
This test project works, but there are some small problems that I know will cause issues down the line, and id like to resolve.
There are two big problems as I see it:
<a routerLink="some/link> does not work in feature modules, only app module: it renders in the markup as plaintext with no working link. I tried importing routerLink to the feature modules module.ts file, as a last ditch effort, but still nothing.
I was hoping that routing to a feature module, if configured that way, could display different mark up and styling, for example- routing to module-a shows one navigation menu, and routing to module-b shows another. Instead, the default behaivor happens- app.component is displayed everywhere, and routing
to a feature module makes the url specified component appear in place of router-outlet. Id like to disable this default behaivor if possible, so that components routed to in one feature module have one set of styles and features, and components routed to in another module have different styling and features- as if router-outlet recognizes that feature-a/component is part of feature-a, and in turn loads that modules' html and css as the app.component instead of the root app.component.
Attached the source code below, for this test project. I only included source for module feature-a, as feature-b is in essence the same thing with different text, to prevent unneeded cluttering
app.module.ts
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { FeatureAModule } from './feature-a/feature-a.module';
import { FeatureBModule } from './feature-b/feature-b.module';
#NgModule({
declarations: [
AppComponent,
],
imports: [
BrowserModule,
AppRoutingModule,
FeatureAModule,
FeatureBModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
App.routing.ts
import { NgModule } from '#angular/core';
import { Routes, RouterModule } from '#angular/router';
import { ChalpComponent } from './feature-a/chalp/chalp.component';
import { FeatureAComponent } from './feature-a/feature-a.component';
import { FeatureBComponent } from './feature-b/feature-b.component';
import { SkoneComponent } from './feature-b/skone/skone.component';
const routes: Routes = [
/* { path: 'feature-a', component: FeatureAComponent,
children: [
{ path : 'feature-a/chalp', component: ChalpComponent }
]
},
{ path: 'feature-b', component: FeatureBComponent,
children: [
{ path : 'feature-b/skone', component: SkoneComponent }
]
}
*/
{ path : 'feature-a/chalp', component: ChalpComponent },
{ path : 'feature-b/skone', component: SkoneComponent },
{ path: 'feature-a', component: FeatureAComponent },
{ path: 'feature-b', component: FeatureAComponent },
];
#NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
markup for app.component:
<h1>Inside App-Module now!</h1>
Go to feature A for chalp: <a routerLink="feature-a/chalp">Chalp</a>
Go to feature B for Skone: <a routerLink="feature-b/skone">Skone</a>
<router-outlet></router-outlet>
feature-a routing + module file
import { NgModule } from '#angular/core';
import { CommonModule } from '#angular/common';
import { RouterModule, Routes, RouterOutlet, RouterLink } from '#angular/router';
import { FeatureAComponent } from './feature-a.component';
import { ChalpComponent } from './chalp/chalp.component';
const routes : Routes = [
{ path : '', component : FeatureAComponent },
{ path : 'chalp', component: ChalpComponent}
]
#NgModule({
declarations: [ChalpComponent],
imports: [
CommonModule,
RouterModule.forChild(routes)
]
})
export class FeatureAModule { }
chalp- a component within feature-a
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-chalp',
templateUrl: './chalp.component.html',
styleUrls: ['./chalp.component.css']
})
export class ChalpComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
}
chalp markup
<p>chalp works!</p>
<a routerLink="../">Go back one</a>
The answer is cleaner:
use lazily loaded feature modules.
// root module routing:
router.forRoot([
// this is what ng documentation suggests
{
path: 'admin',
loadChildren: () => import('./items/items.module').then(m => m.ItemsModule)
},
each of these unique route prefixes
existing already in our bloated application.
now is stored and carefully imported depending
on when the contained resources are required
by the user.
...
])
//then in each feature modules' routing module
router.forChild([
// treat the first word as root, so url is not admin/admin!
{ path: '', component: AdminComponent,
children: [
/*All urls in our app which
have 'admin' prefix*/
]
}
]
Two big lessons out of this excursion into typescript:
always know the framework and the way its designed before using it.
not only do the feature modules handle imports and routing, they also each import
a shared module called util which houses the service main module, all types and interfaces, componentry, pipes and directives that the whole app uses.
In the future, knowing this will help me better design applications. The core app is what
all our feature modules plug into and what gets bootstrapped when the application is served. Now there is a unified structure to how imports and exports are structured, and
you never have a question about how to get to a service or interface.
I am a beginner of Angular2. When I am learning angular2 routing service from https://angular.io/tutorial/toh-pt5. I want to have herocomponent always displayed so I in the app.component.html like this:
<h1>{{title}}</h1>
<nav>
<a routerLink="/dashboard">Dashboard</a>
<a routerLink="/heroes">Heroes</a>
<a routerLink="/dummy">Dummy</a>
</nav>
<app-heroes></app-heroes>
<router-outlet></router-outlet>
<app-messages></app-messages>
And here is the app-routing.module.ts:
import { NgModule } from '#angular/core';
import { RouterModule, Routes } from '#angular/router';
import { DashboardComponent } from './dashboard/dashboard.component';
import { HeroesComponent } from './heroes/heroes.component';
import { HeroDetailComponent } from './hero-detail/hero-detail.component';
import {DummyComponentComponent} from './dummy-component/dummy-component.component';
const routes: Routes = [
{ path: '', redirectTo: '/', pathMatch: 'full' },
{ path: 'dashboard', component: DashboardComponent },
{ path: 'detail/:id', component: HeroDetailComponent },
{ path: 'heroes', component: HeroesComponent },
{path: 'dummy',component:DummyComponentComponent}
];
#NgModule({
imports: [ RouterModule.forRoot(routes) ],
exports: [ RouterModule ]
})
export class AppRoutingModule {}
Strangely, when I click a hero on /dashboard or /heroes page it can direct to the correct URL and show the correct hero detail.
However, when I am on /detail/{{hero.id}} and click the hero on the hero component it can redirect the URL but the content in doesn't update. Can someone please help me with this?
if below is not issue then it should be issue that you are just changing parameter url that is reason its not updating
//put this code in your hero.component.ts file
ngOnInit() {
this.route.params.subscribe((params) => {
this.id = +params['id'];
this.loadComponentAgain();
});
}
above code monitor change in param value and update your component according to it.
There is issue because of this html
<app-heroes></app-heroes>
<router-outlet></router-outlet>
you are loading app-heroes component out side router-outlet, it should be loaded under router-outlet, so you should do this
<!-- <app-heroes></app-heroes> remove this-->
<router-outlet></router-outlet>
For changing a route with dynamic value you need to set your routerLink like this
[routerLink]="['/detail',hero.id]"
first of all let me start by saying I'm fully aware that there are a few similar posts related to this console error.
Normally I would refer to those but I have been using Angular2 from scratch for a total of 5 days and this is the first JS framework that I have ever used so trying to relate my problem to another is proving more difficult. Please bear than in mind before tearing me to shreds!
Now moving on to my problem, I have managed to cobble together a very basic scaffold for a site and I've created several components that I'm basically treating as each "page" of the site (in this case, 'home', 'contact', 'navbar', 'footer'). I have started to try and implement routing so that when the URL = '' you get redirected home, or if you put a specific in, it directs you accordingly.
The problem I'm getting is as soon as the site loads I get this console error: "Error: Error in ./HomeComponent class HomeComponent - inline template:1:20 caused by: Maximum call stack size exceeded".
My search so far has told me that somewhere I've got a recurring function, I tried to eliminate the variables (so far all of my classes contain almost 0 code) but I'm still getting this error.
Here is my app.module.ts
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { RouterModule, Routes } from '#angular/router';
import { FormsModule } from '#angular/forms';
import { HttpModule } from '#angular/http';
import { AppComponent } from './app.component';
import {HomeComponent} from './home/home.component';
import {ContactComponent} from './contact/contact.component';
// import {ProjectListComponent} from './projectlist/projectlist.component';
// import {ProjectDetailComponent} from './projectdetail/projectdetail.component';
// import {ProjectComponent} from './project/project.component';
import {NavbarComponent} from './navbar/navbar.component';
import {FooterComponent} from './footer/footer.component';
const appRoutes: Routes = [
{ path: 'home', component: HomeComponent },
{ path: 'contact', component: ContactComponent },
// { path: 'project/:id', component: ProjectDetailComponent },
// {
// path: 'projects',
// component: ProjectListComponent,
// data: { title: 'Projects List' }
// },
{ path: '',
redirectTo: '/home',
pathMatch: 'full'
},
// { path: '**', component: PageNotFoundComponent }
];
#NgModule({
declarations: [
AppComponent,
HomeComponent,
ContactComponent,
// ProjectListComponent,
// ProjectDetailComponent,
// ProjectComponent,
NavbarComponent,
FooterComponent
],
imports: [
RouterModule.forRoot(appRoutes),
BrowserModule,
FormsModule,
HttpModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
app.component.ts
import { Component } from '#angular/core';
import {HomeComponent} from './home/home.component';
import {ContactComponent} from './contact/contact.component';
// import {ProjectListComponent} from './projectlist/projectlist.component';
// import {ProjectDetailComponent} from './projectdetail/projectdetail.component';
// import {ProjectComponent} from './project/project.component';
import {NavbarComponent} from './navbar/navbar.component';
import {FooterComponent} from './footer/footer.component';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.less']
})
export class AppComponent {
}
home.component.ts
import {Component} from '#angular/core';
import {HomeService} from './home.service';
#Component({
selector: 'home',
templateUrl: './home.component.html',
providers: [HomeService]
})
export class HomeComponent {
private title;
constructor(homeService: HomeService) {
this.title = homeService.getContent();
}
}
I'm not sure if you need my HTML but here is app.component.html
<navigation></navigation>
<router-outlet></router-outlet>
<footer class="footer"></footer>
and home.component.html (like I said it's basic at the moment)
<home>
<h1>{{title}}</h1>
</home>
I'm pretty baffled so far, I realise there is alot to take in and I'm trying to follow a couple of online courses (it's not being made easy by the changes from beta, most courses seem to be quite old at the moment).
Anyway I really do appreciate any help you can offer me and I most definitely appreciate you taking the time to help this noob be a little less noob.
The problem is that your home.component.html has a <home> tag in it. This cause it to infinitely create new home components which results in your maximum call stack size exceeded error.
Angular is trying to render something like:
<home>
<home>
<home>
...
</home>
</home>
</home>