I'm trying to create an application with hash location strategy, but it does not add the hash to the url. For instance when I click on a button associated with { path: '/polls', name: 'Polls', component: PollsComponent } it loads the page with this url : localhost:3000/polls.
What do I have to change to get the hash location strategy?
Why do I have to set the default base url if I want to use hash location strategy?
This is the routing in the app.component.ts where all the routing is defined:
import {Component} from 'angular2/core'
import {HTTP_PROVIDERS, Http} from 'angular2/http';
import 'rxjs/Rx'; // load the full rxjs
import {ROUTER_PROVIDERS, RouteConfig , ROUTER_DIRECTIVES} from 'angular2/router';
import { ResultsComponent } from './results/results.component'
import { VotingCardsComponent } from './votingcards/votingcards.component'
import { DashBoardComponent } from './dash/dash.component'
import { PollsComponent } from './pollslist/pollslist.component'
#Component({
selector: 'my-app',
templateUrl: 'app/app.component.html',
directives: [ROUTER_DIRECTIVES, ResultsComponent, VotingCardsComponent, DashBoardComponent],
providers: [HTTP_PROVIDERS,
ROUTER_PROVIDERS]
})
#RouteConfig([
{ path: '/vote', name: 'VotePage', component: VotingCardsComponent },
{ path: '/votepoll/:id', name: 'VotePoll', component: VotingCardsComponent },
{ path: '/results', name: 'Results', component: ResultsComponent },
{ path: '/polls', name: 'Polls', component: PollsComponent },
{ path: '/', name: 'DashBoard', component: DashBoardComponent, useAsDefault: true }
])
export class AppComponent { }
And this is my main.ts where I configure the base url:
import {bootstrap} from 'angular2/platform/browser';
import {AppComponent} from './app.component';
//this is to avoid the href empty issue
import {provide} from 'angular2/core';
import {APP_BASE_HREF, ROUTER_PROVIDERS} from 'angular2/router';
bootstrap(AppComponent, [
//this is to avoid the href empty issue
ROUTER_PROVIDERS,
provide(LocationStrategy, { useClass: HashLocationStrategy }),
provide(APP_BASE_HREF, { useValue: '/' })
]);
You can use the option "useHash" in RouterModule.forRoot().
RouterModule.forRoot(appRoutes, {useHash: true});
https://discuss.atom.io/t/angular-2-routes-breaking-on-electron-app-refresh/28370/4
ROUTER_PROVIDERS should not be added to child components,
only to
providers: [ROUTER_PROVIDERS]
or alternatively only to
bootstrap(AppComponent, [ROUTER_PROVIDERS]);
HTTP_PROVIDERS are in my opinion also a better fit for root component or bootstrap() but it doesn't break anything to add them somewhere else.
(See also Routing error with angular 2 and IIS)
Everything worked fine with the sample code OP posted as with what is in the accepted answer. But as a minor note, the format required to changing the Hash Location Strategy in the bootstrap file as of RC.4 goes like this:
{ provide: LocationStrategy, useClass: HashLocationStrategy },
It is recommended to use the HTML 5 style (PathLocationStrategy) as location strategy in Angular
Because
It produces the clean and SEO Friendly URLs that are easier for users
to understand and remember.
You can take advantage of the server-side rendering, which will make
our application load faster, by rendering the pages in the server
first before delivering it the client.
Use Hashlocationstrtegy only if you have to support the older
browsers.
Click Here for More info
Related
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 have two pages, home and player, and i want on the home page to nabvigate to the player page but without being with this format home/player
When i use routerLink="player", it got an error because the link goes to home/player, instead of just player. How can i make that happen?
app-routing module:
import { NgModule } from '#angular/core';
import { CommonModule } from '#angular/common';
import {AddPlayerComponent} from './pages/add-player/add-player.component';
import {RouterModule, Routes} from '#angular/router';
import {HomeComponent} from './pages/home/home.component';
const routes: Routes = [
{ path: '', redirectTo: 'home', pathMatch: 'full' },
{ path: 'home', component: HomeComponent },
{ path: 'Player', component: AddPlayerComponent }
];
#NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule {
Try routerLink = "/Player. Notice how in your defined routing module the "Player" is capitalized, as well as the missing "/" in routerLink. See https://angular.io/api/router/RouterLink for more clarification
Try Adding <base href="/"> code in head of index.html page and correct the code to routerLink="/Player".
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>
I have recently moved to Angular2 RC5 from RC4. Since then I have encountered couple of problems. I'm not sure whether these problems are my because of fault or transitional. My app component looks like this :
import {Component, OnInit} from "#angular/core";
import {SetLocationService} from "./auth/set-location.service";
#Component({
selector : "my-app",
template: `
<app-header></app-header>
<router-outlet></router-outlet>
<app-footer></app-footer>
`
})
export class AppComponent implements OnInit{
constructor(
private _setLocationService : SetLocationService
){}
ngOnInit() {
this._setLocationService.setLocation();
}
}
routing :
import {Routes, RouterModule} from '#angular/router';
import {SearchBoxComponent} from "./search/searchBox.component";
import {SearchResultComponent} from "./search/search-result.component";
import {LoginComponent} from "./auth/login.component";
import {SignupComponent} from "./auth/signup.component";
import {LogoutComponent} from "./auth/logout.component";
import {RecoverPasswordComponent} from "./auth/recover-password.component";
import {ProfileComponent} from "./auth/profile.component"
import {AccountComponent} from "./auth/account.component"
const appRoutes: Routes = [
{path : '', component: SearchBoxComponent},
{path : 'login', component: LoginComponent},
{path : 'signup', component: SignupComponent},
{path : 'logout', component: LogoutComponent},
{path : 'profile', component: ProfileComponent},
{path : 'account', component: AccountComponent},
{path : 'user/:uname', component: SearchBoxComponent},
{path : 'recover-password', component: RecoverPasswordComponent},
{path : 'search/:params', component: SearchResultComponent},
{path : '**', component : SearchBoxComponent}
];
export const routing = RouterModule.forRoot(appRoutes);
app module :
// #Modules -> Modules
import {BrowserModule} from '#angular/platform-browser';
import {FormsModule} from '#angular/forms';
import {HttpModule} from '#angular/http';
import {LocationStrategy, HashLocationStrategy} from '#angular/common';
import {NgModule} from '#angular/core';
// import {RouterModule} from '#angular/router';
// #Routes -> routes
import {routing} from "./app.routes";
// #Components - > Components
import {AccountComponent} from "./auth/account.component";
import {AppComponent} from './app.component';
import {ChatBoxComponent} from "./chat/chat-box.component";
import {ChatBoxDirective} from "./chat/chat-box.directive";
import {FooterComponent} from "./layout/footer.component";
import {HeaderComponent} from "./layout/header.component";
import {LoginComponent} from "./auth/login.component";
import {LogoutComponent} from "./auth/logout.component";
import {ProfileComponent} from "./auth/profile.component";
import {RecoverPasswordComponent} from "./auth/recover-password.component";
import {SearchBoxComponent} from "./search/searchBox.component";
import {SearchResultComponent} from "./search/search-result.component";
import {SignupComponent} from "./auth/signup.component";
// #providers - > services
import {AuthService} from "./auth/auth.service";
import {SetLocationService} from "./auth/set-location.service";
import {SearchService} from "./search/search.service";
#NgModule({
imports: [
BrowserModule,
FormsModule,
HttpModule,
routing
],
declarations: [
AccountComponent,
AppComponent,
ChatBoxComponent,
ChatBoxDirective,
FooterComponent,
HeaderComponent,
LoginComponent,
LogoutComponent,
ProfileComponent,
RecoverPasswordComponent,
SearchBoxComponent,
SearchResultComponent,
SignupComponent
],
providers : [
AuthService,
SetLocationService,
SearchService,
{provide: LocationStrategy, useClass: HashLocationStrategy}
],
bootstrap: [
AppComponent,
HeaderComponent,
FooterComponent
]
})
export class AppModule {}
My first problem is if I do not add 1.HeaderComponent, 2.FooterComponent in bootstrap of app.module, none of them(1.HeaderComponent, 2.FooterComponent) get loaded when root route is active (localhost:3000), but the SearchBoxComponent. I am kind of confused, since I did not see adding multiple components in bootstrap this in the official document.
My second problem is almost same as the first one. If I embed a component (seachBoxConmponent) in another component like the following code, seachBoxConmponent component does not get loaded but the other parts.
#Component({
selector: "search-result",
template : `
<seachBox></searchBox>
<div class="tag_list">
<p *ngFor = "let tag of result.obj.tags" class = "tag-li" >
<a [routerLink] = "['/search', tag]" (click) = "onSearchCliked($event, tag)"> {{tag}} </a>
</p>
</div>
`
})
I was wondering , can anyone please help me, I have been working on this problem for last couple of days, still I am stuck here.
Make sure the module that declares a component exports it. Otherwise this component will not be visible to other components trying to use it.
I would suggest creating separate modules for discrete concerns such as search, signup, chat, etc. and following the pattern below to share their components.
I've noticed that Angular2 fails silently when a component being used is not in scope. You'll add a component to the template and it'll just not render, no error. Before RC5 it usually meant you did not specify the desired component in the directives:[] array. With RC5, it probably means you're not exporting the component from the module that declares it and/or importing it in the module that wants to use it.
FooModule declares and exports FooComponent, exposing it for use by other components (potentially in other modules):
#NgModule({
declarations: [FooComponent],
imports: [BrowserModule, FormsModule],
exports: [FooComponent]
})
export class FooModule {}
FooComponent:
#Component({
selector: 'foo',
template: `FOO`
})
export class FooComponent {}
BarModule imports FooModule, gaining access to the components it exposes (namely FooComponent):
#NgModule({
declarations: [BarComponent],
imports: [FooModule, FormsModule],
exports: [BarComponent]
})
export class BarModule {}
BarComponent can access FooComponent and use it in the template:
#Component({
selector: 'bar',
template: `<foo></foo>BAR`
})
export class BarComponent {}
I'm having all sorts of trouble migrating to RC5 too, but only AppComponent should be in your bootstrap. If you only get to a component via the router, then that component should not be in declarations. But that component should use export default class ComponentName.
the way I've been attacking this is commenting everything out and adding components and services one at a time.
Thank you guys for helping me. Finally, I solved the problem. I was actually including ROUTER_DIRECTIVES in HeaderComponent and FooterComponenet. These are the places where conflicts occur. It is because "RouterModule" implicitly provides ROUTER_DIRECTIVES. So, we do not have to include the directive again in any component. I removed this directive and that fixes my problem after almost a week later. I also had to change the old fashioned routerLike style according to the docs.
#Alex Sartan : Thanks very much for explaining the details of the problem. I fix the problem without creating separate modules for discrete concerns. But this is better to keep all the concerns separate. I appreciate your help.
I am taking my first steps with Angular 2 and angular in general, and I am wondering how to setup a landing page.
My goal is to show a landingpage everytime the user does not have a token in local storage or in a cookie.
My app.component.ts looks like this
import {Component} from 'angular2/core';
import {ROUTER_DIRECTIVES, RouteConfig} from 'angular2/router';
import {NavbarComponent} from './navbar.component';
import {LoaderComponent} from './loader.component';
import {NameListService} from '../shared/index';
import {HomeComponent} from '../+home/index';
import {AboutComponent} from '../+about/index';
#Component({
selector: 'g-app',
viewProviders: [NameListService],
templateUrl: 'app/components/app.component.html',
directives: [ROUTER_DIRECTIVES, NavbarComponent, LoaderComponent]
})
#RouteConfig([
{
path: '/',
name: 'Home',
component: HomeComponent
},
{
path: '/about',
name: 'About',
component: AboutComponent
}
])
export class AppComponent {
}
/home and /about are also components if I understand correctly. Now I would like to have a seperate page that doesn't have access to the navbar. Which is what the user will always land on if he isn't logged in.
Would be awesome if someone could help me start out or atleast point me in a good direction, maybe point me to a good angular 2 tutorial.
This is the boilerplate I am basing my app on https://github.com/mgechev/angular2-seed
You can override the router-outlet and check on activation, if the token is present. Something like this:
import {Directive, Attribute, ElementRef, DynamicComponentLoader} from 'angular2/core';
import {Router, RouterOutlet, ComponentInstruction} from 'angular2/router';
#Directive({
selector: 'router-outlet'
})
export class LoggedInRouterOutlet extends RouterOutlet {
publicRoutes: any;
private parentRouter: Router;
constructor(_elementRef: ElementRef, _loader: DynamicComponentLoader,
_parentRouter: Router, #Attribute('name') nameAttr: string) {
super(_elementRef, _loader, _parentRouter, nameAttr);
this.parentRouter = _parentRouter;
}
activate(instruction: ComponentInstruction) {
if (!hasToken()) {
this.parentRouter.navigateByUrl('/login');
}
return super.activate(instruction);
}
}
Adapted from here: https://github.com/auth0-blog/angular2-authentication-sample/blob/master/src/app/LoggedInOutlet.ts
This can be extended to be able to work with roles and other access controlls.
You can just redirect to a specific route on load when the token is not available.
export class AppComponent {
constructor(private router:Router) {
if(!hasToken()) {
router.navigate(['/LoginForm']);
}
}
}
Alternatively you can create a custom RouterOutlet that checks for each route if it is allowed for the user to navigate to that route like explained in http://www.captaincodeman.com/2016/03/31/angular2-route-security/