284
votes

Obviously the beta for Angular2 is newer than new, so there's not much information out there, but I am trying to do what I think is some fairly basic routing.

Hacking about with the quick-start code and other snippets from the https://angular.io website has resulted in the following file structure:

angular-testapp/
    app/
        app.component.ts
        boot.ts
        routing-test.component.ts
    index.html

With the files being populated as follows:

index.html

<html>

  <head>
    <base href="/">
    <title>Angular 2 QuickStart</title>
    <link href="../css/bootstrap.css" rel="stylesheet">

    <!-- 1. Load libraries -->
    <script src="node_modules/angular2/bundles/angular2-polyfills.js"></script>
    <script src="node_modules/systemjs/dist/system.src.js"></script>
    <script src="node_modules/rxjs/bundles/Rx.js"></script>
    <script src="node_modules/angular2/bundles/angular2.dev.js"></script>
    <script src="node_modules/angular2/bundles/router.dev.js"></script>

    <!-- 2. Configure SystemJS -->
    <script>
      System.config({
        packages: {        
          app: {
            format: 'register',
            defaultExtension: 'js'
          }
        }
      });
      System.import('app/boot')
            .then(null, console.error.bind(console));
    </script>

  </head>

  <!-- 3. Display the application -->
  <body>
    <my-app>Loading...</my-app>
  </body>

</html>

boot.ts

import {bootstrap}    from 'angular2/platform/browser'
import {ROUTER_PROVIDERS} from 'angular2/router';

import {AppComponent} from './app.component'

bootstrap(AppComponent, [
    ROUTER_PROVIDERS
]);

app.component.ts

import {Component} from 'angular2/core';
import {RouteConfig, ROUTER_DIRECTIVES, ROUTER_PROVIDERS, LocationStrategy, HashLocationStrategy} from 'angular2/router';

import {RoutingTestComponent} from './routing-test.component';

@Component({
    selector: 'my-app',
    template: `
        <h1>Component Router</h1>
        <a [routerLink]="['RoutingTest']">Routing Test</a>
        <router-outlet></router-outlet>
        `
})

@RouteConfig([
    {path:'/routing-test', name: 'RoutingTest', component: RoutingTestComponent, useAsDefault: true},
])

export class AppComponent { }

routing-test.component.ts

import {Component} from 'angular2/core';
import {Router} from 'angular2/router';

@Component({
    template: `
        <h2>Routing Test</h2>
        <p>Interesting stuff goes here!</p>
        `
})
export class RoutingTestComponent { }

Attempting to run this code produces the error:

EXCEPTION: Template parse errors:
Can't bind to 'routerLink' since it isn't a known native property ("
        <h1>Component Router</h1>
        <a [ERROR ->][routerLink]="['RoutingTest']">Routing Test</a>
        <router-outlet></router-outlet>
        "): AppComponent@2:11

I found a vaguely related issue here; router-link directives broken after upgrading to angular2.0.0-beta.0. However, the "working example" in one of the answers is based on pre-beta code - which may well still work, but I would like to know why the code I have created is not working.

Any pointers would be gratefully received!

12
The other question has something different : directives: [ROUTER_DIRECTIVES].Eric Martinez
I am getting the same error even with ROUTER_DIRECTIVES. @Component({selector: "app"}) @View({templateUrl: "app.html", directives: [ROUTER_DIRECTIVES, RouterLink]})phil
With the addition of directives: [ROUTER_DIRECTIVES] and changing from [router-link] to [routerLink] I am no longer getting the error.phil
I was getting the same error (NG8002: Can't bind to 'routerLink' since it isn't a known property of 'a'). I did not use the cli while creating the component. I forgot to add the component declaration in my module. Adding the component names in the declaration array fixed it for me.Charanraj Golla

12 Answers

401
votes

>=RC.5

import the RouterModule See also https://angular.io/guide/router

@NgModule({ 
  imports: [RouterModule],
  ...
})

>=RC.2

app.routes.ts

import { provideRouter, RouterConfig } from '@angular/router';

export const routes: RouterConfig = [
  ...
];

export const APP_ROUTER_PROVIDERS = [provideRouter(routes)];

main.ts

import { bootstrap } from '@angular/platform-browser-dynamic';
import { APP_ROUTER_PROVIDERS } from './app.routes';

bootstrap(AppComponent, [APP_ROUTER_PROVIDERS]);

<=RC.1

Your code is missing

  @Component({
    ...
    directives: [ROUTER_DIRECTIVES],
    ...)}

You can't use directives like routerLink or router-outlet without making them known to your component.

While directive names were changed to be case-sensitive in Angular2, elements still use - in the name like <router-outlet> to be compatible with the web-components spec which require a - in the name of custom elements.

register globally

To make ROUTER_DIRECTIVES globally available, add this provider to bootstrap(...):

provide(PLATFORM_DIRECTIVES, {useValue: [ROUTER_DIRECTIVES], multi: true})

then it's no longer necessary to add ROUTER_DIRECTIVES to each component.

118
votes

For people who find this when attempting to run tests because via npm test or ng test using Karma or whatever else. Your .spec module needs a special router testing import to be able to build.

import { RouterTestingModule } from '@angular/router/testing';

TestBed.configureTestingModule({
    imports: [RouterTestingModule],
    declarations: [AppComponent],
});

http://www.kirjai.com/ng2-component-testing-routerlink-routeroutlet/

25
votes

Word of caution when coding with Visual Studio (2013)

I have wasted 4 to 5 hours trying to debug this error. I tried all the solutions that I found on StackOverflow by the letter and I still got this error: Can't bind to 'routerlink' since it isn't a known native property

Be aware, Visual Studio has the nasty habit of autoformatting text when you copy/paste code. I always got a small instantaneous adjustment from VS13 (camel case disappears).

This:

<div>
    <a [routerLink]="['/catalog']">Catalog</a>
    <a [routerLink]="['/summary']">Summary</a>
</div>

Becomes:

<div>
    <a [routerlink]="['/catalog']">Catalog</a>
    <a [routerlink]="['/summary']">Summary</a>
</div>

It's a small difference, but enough to trigger the error. The ugliest part is that this small difference just kept avoiding my attention every time I copied and pasted. By sheer chance, I saw this small difference and solved it.

13
votes

For >= V5

import { RouterModule, Routes } from '@angular/router';

const appRoutes: Routes = [
    {path:'routing-test', component: RoutingTestComponent}
];

@NgModule({
    imports: [
    RouterModule.forRoot(appRoutes)
    // other imports here
    ]
})

component:

@Component({
    selector: 'my-app',
    template: `
        <h1>Component Router</h1>
        <a routerLink="/routing-test" routerLinkActive="active">Routing Test</a>
        <router-outlet></router-outlet>
        `
})

For < V5

Also can use RouterLink as a directives ie. directives: [RouterLink]. that worked for me

import {Router, RouteParams, RouterLink} from 'angular2/router';

@Component({
    selector: 'my-app',
    directives: [RouterLink],
    template: `
        <h1>Component Router</h1>
        <a [routerLink]="['RoutingTest']">Routing Test</a>
        <router-outlet></router-outlet>
        `
})

@RouteConfig([
    {path:'/routing-test', name: 'RoutingTest', component: RoutingTestComponent, useAsDefault: true},
])
11
votes

In general, whenever you get an error like Can't bind to 'xxx' since it isn't a known native property, the most likely cause is forgetting to specify a component or a directive (or a constant that contains the component or the directive) in the directives metadata array. Such is the case here.

Since you did not specify RouterLink or the constant ROUTER_DIRECTIVES – which contains the following:

export const ROUTER_DIRECTIVES = [RouterOutlet, RouterLink, RouterLinkWithHref, 
  RouterLinkActive];

– in the directives array, then when Angular parses

<a [routerLink]="['RoutingTest']">Routing Test</a>

it doesn't know about the RouterLink directive (which uses attribute selector routerLink). Since Angular does know what the a element is, it assumes that [routerLink]="..." is a property binding for the a element. But it then discovers that routerLink is not a native property of a elements, hence it throws the exception about the unknown property.


I've never really liked the ambiguity of the syntax. I.e., consider

<something [whatIsThis]="..." ...>

Just by looking at the HTML we can't tell if whatIsThis is

  • a native property of something
  • a directive's attribute selector
  • a input property of something

We have to know which directives: [...] are specified in the component's/directive's metadata in order to mentally interpret the HTML. And when we forget to put something into the directives array, I feel this ambiguity makes it a bit harder to debug.

7
votes

You have in your module

import {Routes, RouterModule} from '@angular/router';

you have to export the module RouteModule

example:

@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule]
})

to be able to access the functionalities for all who import this module.

5
votes

I have tried all methods, which are mentioned above.But no one method works for me.finally i got solution for above issue and it is working for me.

I tried this method:

In Html:

<li><a (click)= "aboutPageLoad()"  routerLinkActive="active">About</a></li>

In TS file:

aboutPageLoad() {
    this.router.navigate(['/about']);
}
5
votes

In my case I have imported the RouterModule in App module but not imported in my feature module. After import the router module in my EventModule the error goes away.

    import {NgModule } from '@angular/core';
    import { BrowserModule } from '@angular/platform-browser';
    import {EventListComponent} from './EventList.Component';
    import {EventThumbnailComponent} from './EventThumbnail.Component';
    import { EventService } from './shared/Event.Service'
    import {ToastrService} from '../shared/toastr.service';
    import {EventDetailsComponent} from './event-details/event.details.component';
    import { RouterModule } from "@angular/router";
    @NgModule({
      imports:[BrowserModule,RouterModule],
      declarations:[EventThumbnailComponent,EventListComponent,EventDetailsComponent],
      exports: [EventThumbnailComponent,EventListComponent,EventDetailsComponent],
       providers: [EventService,ToastrService]
    })
    export class EventModule {
        
     }
3
votes

If getting this error while unit testing please write this.

import { RouterTestingModule } from '@angular/router/testing';
beforeEach(async(() => {
  TestBed.configureTestingModule({
    imports: [RouterTestingModule],
    declarations: [AppComponent],
  });
}));
0
votes

If you use shared modules, just add RouterModule to a Module where your component is declared and don't forget to add <router-outlet></router-outlet>

Referenced from here RouterLink does not work

0
votes

I really appreciate @raykrow's answer when one has this problem only in a test file! That is where I encountered it.

As it is often helpful to have another way to do something as a backup, I wanted to mention this technique that also works (instead of importing RouterTestingModule):

import { MockComponent } from 'ng2-mock-component';
. . .
TestBed.configureTestingModule({
  declarations: [
    MockComponent({
      selector: 'a',
      inputs: [ 'routerLink', 'routerLinkActiveOptions' ]
    }),
    . . .
  ]

(Typically, one would use routerLink on an <a> element but adjust the selector accordingly for other components.)

The second reason I wanted to mention this alternate solution is that, though it served me well in a number of spec files, I ran into a problem with it in one case:

Error: Template parse errors:
    More than one component matched on this element.
    Make sure that only one component's selector can match a given element.
    Conflicting components: ButtonComponent,Mock

I could not quite figure out how this mock and my ButtonComponent were using the same selector, so searching for an alternate approach led me here to @raykrow's solution.

-4
votes

My solution is simple. I am using [href] instead of [routerLink]. I have tried all solutions for [routerLink]. None of them works in my case.

Here is my solution:

<a [href]="getPlanUrl()" target="_blank">My Plan Name</a>

Then write the getPlanUrl function in the TS file.