1

I'm trying to create a wizard using Angular2's router. Angular2 suggests to have a main bootstrap file, which will bootstrap all the app components. Since i'm not able to do a SPA, i would like each page to bootstrap it's own components.

I get the following error about routerLink when i run the application:

"EXCEPTION: Template parse errors: Can't bind to 'routerLink' since it isn't a known native property ("For="#wizard of Wizards" [selected]="SelectedWizard == wizard" [value]="wizard.name" [ERROR ->][routerLink]="'' + wizard.path + ''">{{wizard.name}} "

Here is my page component:

/// <reference path="angular2/typings/browser.d.ts" />
/// <reference path="angular2/core.d.ts" />
/// <reference path="angular2/router.d.ts" />

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

import {Wizard1} from './wizard1';
import {Wizard2} from './wizard2';
import {Step1} from './step1';
import {Step2} from './step2';
import {Step3} from './step3';
import {Step4} from './step4';
import {Step5} from './step5';

@Component({
    selector: 'page',
    template:
'<div>
    <select (change)="setSelectedWizard($event.target.value)">
        <option *ngFor="#wizard of Wizards" [selected]="SelectedWizard == wizard" [value]="wizard.name" [routerLink]="'' + wizard.path + ''">{{wizard.name}}</option>
    </select>
    <wizard1>
        <step1>
            <h1>First!</h1>
        </step1>
        <step2>
            <h1>Second!</h1>
        </step2>
        <step3>
            <h1>Third!</h1>
        </step3>
        <step4>
            <h1>Fourth!</h1>
        </step4>
        <nav>
            <button type="button" value="Next" [class]="(SelectedStepIndex == Steps.length) ? 'btn btn-primary hidden' : 'btn btn-default'" (click)="next()" [routerLink]="['' + Steps[SelectedStepIndex] + '']">Next</button>
        </nav>
        <router-outlet></router-outlet>
    </wizard1>
    <wizard2>
        <step1>
            <h1>First!</h1>
        </step1>
        <step5>
            <h1>Fifth!</h1>
        </step5>
        <nav>
            <button type="button" value="Next" [class]="(SelectedStepIndex == Steps.length) ? 'btn btn-primary hidden' : 'btn btn-default'" (click)="next()" [routerLink]="['' + Steps[SelectedStepIndex] + '']">Next</button>
        </nav>
        <router-outlet></router-outlet>
    </wizard2>
    <router-outlet></router-outlet>
</div>'
})
export class Page {
    Wizards = [{name: 'wizard1', path:'/wizard1'}, {name: 'wizard2', path: '/wizard2'}];
    SelectedWizard = this.Wizards[0];

    setSelectedWizard(value) {
       this.SelectedWizard = value;
    }
}

bootstrap(Page, [ROUTER_PROVIDERS]);
bootstrap(Wizard1, [ROUTER_PROVIDERS]);
bootstrap(Wizard2, [ROUTER_PROVIDERS]);
bootstrap(Step1);
bootstrap(Step2);
bootstrap(Step3);
bootstrap(Step4);
bootstrap(Step5);

Wizard1

/// <reference path="angular2/core.d.ts" />
/// <reference path="angular2/router.d.ts" />

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

@RouteConfig([
    { path: '/wizard1', name: 'wizard1', component: Wizard1 }
])
@Component({
    selector: 'wizard1',
    template:`<div><ng-content></ng-content></div>`
})
export class Wizard1 {
    Steps = ['/Step1', '/Step2', '/Step3', '/Step4'];
    SelectedStepIndex = 0;

    next() {
        ++this.SelectedStepIndex;
    }
}

Wizard2

/// <reference path="angular2/core.d.ts" />
/// <reference path="angular2/router.d.ts" />

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

@RouteConfig([
    { path: '/wizard2', name: 'wizard2', component: Wizard2 }
])
@Component({
    selector: 'wizard2',
    template:`<div><ng-content></ng-content></div>`
})
export class Wizard2 {
    Steps = ['/Step1', '/Step5'];
    SelectedStepIndex = 0;

    next() {
        ++this.SelectedStepIndex;
    }
}

All steps are similar to this, in their own .ts files

/// <reference path="angular2/core.d.ts" />
/// <reference path="angular2/router.d.ts" />

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

@RouteConfig([
    { path: '/Step1', name: 'Step1', component: Step1 }
])
@Component({
    selector: 'step1',
    template: `<div><ng-content></ng-content></div>`
})
export class Step1 {

}

What is going on? why isn't this working?

Environment

  1. Visual Studio 2015 update 1
  2. ASP.NET 5 and MVC 6
  3. DNX 4.5.1 and 5.0
  4. Angular2 Typescript

2 Answers2

1

You are missing ROUTER_DIRECTIVES is missing to import on Page components & directives option of ComponentMetaData, that is the reason why angular doesn't understand routerLink & routerOutlet directive on page. Do include below line

import {ROUTER_PROVIDERS, ROUTER_DIRECTIVES} from 'angular2/router';

Then obviously inject ROUTER_DIRECTIVES in that component directives option

@Component({
    selector: 'page',
    //....
    //other options
    //....
    directives: [ROUTER_DIRECTIVES]
})

I'm not sure why you did bootstrap you application multiple times? Ideally there should be only one main-component, other component will child of it.

Pankaj Parkar
  • 134,766
  • 23
  • 234
  • 299
  • It's not a single page application. You will have a root like you said in SPA. In my case every page is the root component. –  Apr 15 '16 at 20:16
  • @Hani having `main-component` is not `SPA` specific stuff.. you could have single app root in this case too, isn't it? And what about the error which you are getting? does that gets solved? – Pankaj Parkar Apr 15 '16 at 20:18
  • My page is the root. Yes, i can place the bootstrapping in a separate file but then i'll need such a file for every page. In SPA, you would have one such bootstrap. –  Apr 15 '16 at 20:20
  • Hmmm... now it says Steps is undefined. Does this mean that the scope is still the parent page? –  Apr 15 '16 at 20:26
  • 1
    @Hani there is no Child & Parent scope concept in A2.. – Pankaj Parkar Apr 16 '16 at 11:35
1

Add ROUTER_DIRECTIVES to your component providers:

@Component({directives: [ROUTER_DIRECTIVES]})
kemsky
  • 14,727
  • 3
  • 32
  • 51