angular: Using router-link to navigate to another component does not invoke the onInit method

I’m using Angular alpha.39 version, ES6 and router-link to navigate to a child component. I use Babel to transpile the code.

In the following example, I have a dashboard component which has a WinJS splitterview. In the navigation area of splitview, I have a link to display the people component in the content area of the split view.

The problem is when I click the people link in the navigation area of the dashboard component, I see that the constructor of the people component is called but not the onInit method. I have to do some DOM manipulation in the onInit which I can’t do because of this. If I put the DOM manipulation in the constructor, it will work.

dashboard.html

<base href="/dashboard/">

<div id="app">
    <div class="splitView" data-win-control="WinJS.UI.SplitView" data-win-options="{ openedDisplayMode : 'inline' }">
        <div>
            <div class="header">
                <button class="win-splitviewpanetoggle"
                        data-win-control="WinJS.UI.SplitViewPaneToggle"
                        data-win-options="{ splitView: select('.splitView') }"></button>
                <div class="title">SplitView Pane area</div>
            </div>
            <div class="nav-commands">
                <a [router-link]="['/People']">People</a>
            </div>
        </div>
        <div class="contenttext">
            <router-outlet></router-outlet>
        </div>
    </div>
</div>

app.js

import { Component, View, bootstrap,  bind } from 'angular2/angular2';
import { RouteConfig, ROUTER_BINDINGS, ROUTER_DIRECTIVES, ROUTER_PRIMARY_COMPONENT } from 'angular2/router';
import 'reflect-metadata';
import 'winjs';
import { PeopleComponent } from './people/people'

@Component({
    selector: 'dashboard-app'
})
@View({
    templateUrl: './dashboard/dashboard.html',
    directives: [ ROUTER_DIRECTIVES ]
})
@RouteConfig([
    { path: '/people', component: PeopleComponent, as: 'People'} 
]) 
class DashboardAppComponent {
    constructor() {
    }

    onInit() {
        WinJS.UI.processAll().done(function() {
            var splitView = document.querySelector(".splitView").winControl;
            new WinJS.UI._WinKeyboard(splitView.paneElement);
        })
    }
}

bootstrap(DashboardAppComponent, [ ROUTER_BINDINGS, bind(ROUTER_PRIMARY_COMPONENT).toValue(DashboardAppComponent) ]);

people.html

<div id="tileview"></div>

people.js

import { Component, View, bootstrap } from 'angular2/angular2';
import 'reflect-metadata';
import 'globalize';

@Component({
    selector: 'people'
})
@View({
    templateUrl: './people/people.html',
})
export class PeopleComponent {
    constructor() {
    // THIS GETS CALLED WHEN I CLICK PEOPLE IN THE DASHBOARD
    }

    onInit() {
    // THIS NEVER GETS CALLED
    }
}

About this issue

  • Original URL
  • State: closed
  • Created 9 years ago
  • Reactions: 8
  • Comments: 41 (11 by maintainers)

Most upvoted comments

+1 I’m having this issue, when i click a link the first time, the template shows but no binding occur, when i click the same link again the bindings working.

Is there any update on this issue? I’m having the same trouble. ngOnInit() is being called successfully in the primary component but the child component ngOnInit() don’t seem to work once routed to from the parent component.

@coryshaw1 one thing that jumps out to me in looking at your demo is that you have the OnPush ChangeDetectionStrategy on your demo.ts component. This strategy is usually used with Observables or changes in input that informs Angular that change detection needs to be run. Remove the OnPush from your demo.ts component and test your pagination route again.

Thank you @cvwilliams! That did the trick for me too.

The answer that helped me in that thread was: “system-polyfills has to be loaded before angular2-polyfills”.

On Angular 7 and still having this issue. This is the 2nd issue with the router that I’ve come across this week that was closed “in an effort to make the new router more robust” without the issue actually being fixed in the new router (which we’re using).

Here is the order i have loading

<script src="~/lib/shims/es6-shim.js"></script>
<script src="~/lib/shims/system-polyfills.js"></script>
<script src="~/lib/shims/angular2-polyfills.js"></script>
<script src="~/lib/shims/shims_for_ie.js"></script>

then in a combined file i create i load the following in this order

systemjs/dist/system.src.js
angular2/bundles/angular2.dev.js
angular2/bundles/router.dev.js
angular2/bundles/http.dev.js
rxjs/bundles/Rx.js
lodash/lodash.js
jquery/dist/jquery.js
bootstrap/dist/js/bootstrap.js
ng2-bs3-modal/bundles/ng2-bs3-modal.js

then i load my app.js for all my angular 2 components

Current versions i have all working:

“angular2”: “2.0.0-beta.9”, “bootstrap”: “^3.3.6”, “es6-promise”: “^3.1.2”, “es6-shim”: “^0.35.0”, “font-awesome”: “^4.5.0”, “reflect-metadata”: “0.1.3”, “rxjs”: “^5.0.0-beta.3”, “systemjs”: “^0.19.24”, “zone.js”: “0.5.15”, “ng2-bs3-modal”: “0.4.2”, “jquery”: “2.2.2”, “lodash”: “^4.6.1”

http://stackoverflow.com/a/35058096 <- This stack overflow helped me with this issue @micahosborne @YanisJ @coryshaw1. Hope this helps

Update I used zone to send the navigate and it renders okay

We are no longer maintaining the deprecated router to focus our efforts on making the new router robust.

It doesn’t look like the issue makes sense in the context of the new router. If you think it does, please reopen the issue.

Closing this issue.

have the same problem. onInit wont be called if i hit the back button in safari Version 9.1 (11601.5.17.1).

using “angular2”: “2.0.0-beta.11”, and “systemjs”: “0.19.24”,

include order:

<script src="node_modules/es6-shim/es6-shim.min.js"></script>
<script src="node_modules/systemjs/dist/system-polyfills.js"></script>
<script src="node_modules/angular2/bundles/angular2-polyfills.js"></script>
<script src="node_modules/systemjs/dist/system.src.js"></script>

edit: works fine with chrome, though.

I am still seeing this issue and have no ChangeDetectionStrategy in place.
Any news on other possibilities for this issue? Current Versions : “angular2”: “^2.0.0-beta.11”, “systemjs”: “^0.19.24”, “es6-promise”: “^3.1.2”, “es6-shim”: “^0.35.0”, “reflect-metadata”: “^0.1.3”, “rxjs”: “^5.0.0-beta.3”, “zone.js”: “^0.6.5”,

Wether i refresh the page or click on the route link on a fresh page load, i need to always click the link twice to get the data to load

Parent App Component

import {Component} from 'angular2/core';
import {RouteConfig, ROUTER_DIRECTIVES, RouterOutlet} from 'angular2/router';
import {HeaderComponent} from '../Layout/header.component';
import {ActionbarComponent} from "../Layout/actionbar.component";
import {SidebarComponent} from "../Layout/sidebar.component";
import {FooterComponent} from "../Layout/footer.component";
import {LoggingService} from '../Shared/Services/logging.service';
import {PolicyService} from './Services/policy.service';
import {PolicyListComponent} from './policylist.component';

@Component({
    selector: 'my-app',
    templateUrl: 'views/policymanager.view.html',
    providers: [LoggingService, PolicyService],
    directives: [HeaderComponent, ActionbarComponent, SidebarComponent, FooterComponent, PolicyListComponent, RouterOutlet]
})
@RouteConfig([
    { path: '/policies', name: 'PolicyList', component: PolicyListComponent }
])
export class AppComponent {
    constructor(private loggingService: LoggingService) { }
    title = 'Policy Manager';
}

Child component that should load in router-outlet


import {Component, ChangeDetectorRef, OnInit} from 'angular2/core';
import {LoggingService} from '../Shared/Services/logging.service';
import {PolicyService} from './Services/policy.service';

@Component({
    selector: 'one-policylist',
    //templateUrl: 'views/policylist.view.html'
    template: "
    <ul *ngIf="policies.length > 0">
    <li *ngFor="#policy of policies">
        {{ policy.Id }} - {{ policy.PolicyNumber }} - {{ policy.Name }}
    </li>
</ul>
<div *ngIf="policies.length == 0">
    retriving policies...
</div>
"  
})
export class PolicyListComponent implements OnInit {
    public policies: Array<Object> = [];
    constructor(private loggingService: LoggingService, private policyService: PolicyService) { }
    ngOnInit() {
        //this will not fire on first load of the route
        this.policyService.getPolicies().subscribe(
            data => this.processData(data),
            err => this.logError(err, "getPolicies"),
            () => this.loggingService.debug("get policies complete")); 
    }

    private processData(data) {
        this.policies = data;
        console.log(this.policies);
    }

    logError(err, methodName) {
        //show user message
        var error = "Unknown error occurred";
        var errObj = JSON.parse(err._body);
        if (errObj.Errors.length > 0) {
            error = errObj.Errors[0].ErrorCode + ":" + errObj.Errors[0].ErrorMessage;
        }
        var message = this.loggingService.buildErrorMessage(error, err.status, methodName, [errObj, {"test": "one", "lister": [{"inner": 1, "inner2": 2}]}]);
        this.loggingService.error(message);
    }
}

*Update: * Found the issue, while i had the system ployfills listed in the correct order, in my gulp file it was getting added again after the angular2.dev.js which was causing havoc. UGH. Thanks @brandonroberts for the polyfill mention which got me back on track.

@brandonroberts good catch! Yeah we refactored our demos to be modular, and used to have everything on one page without a router. That OnPush change detection must have been left over from the old demo component. So using ChangeDetectionStrategy.OnPush on a component that uses router-outlet will botch the initial load.