6

Background

Suppose I have some parent component, call it MatchList, that presents a list of Hero objects, among other things. Each Hero object has properties that are shown in some table. Now suppose I also have a button for each Hero that updates the route, loads a new view, and shows more details.

Before

http://heroic.com/match-list

After

http://heroic.com/hero-84

Problem

My problem essential is this: I want to call the router's navigate() method from a button in my MatchList template, but I receive the following error when I attempt to do so:

EXCEPTION: Error during evaluation of "click"BrowserDomAdapter.logError @ ... angular2.dev.js:21835 ORIGINAL EXCEPTION: TypeError: l_context.setPath is not a function... angular2.dev.js:21835 TypeError: l_context.setPath is not a function at ...

In other words It looks like I cannot reference the parent component's router methods in the child template.

So, what is the correct and best way in Angular 2 for a child component access the methods of the parent component ( or 'context')?

I'd prefer if the solution was something cleaner than

class parent {

     child: Child;

     constructor(...) {

        ...

        this.child.parent = this;

     }
}

Sample Code

EDIT I changed my template button to

(^click)="setPath(match.match_id)"

I am not longer receiving an error message, but nothing happens - I don't even get a console log confirming the click.


Snippets of what I have so far.

//Parent

    @Component({
        selector: 'dota-app',
        directives: [Home, MatchesView, ROUTER_DIRECTIVES],
        templateUrl: 'AppView.html'
    })
    @RouteConfig([
        { path: '/', component: Home, as: 'Home' },
        { path: '/matches', component: MatchesView, as: 'Matches' },
        { path: '/match-details', component: MatchDetailsView, as: 'MatchDetails'}
    ])
    export class RootDotaComponent {

        router: Router;

        constructor(router: Router) {

            this.router = router;

        }

        public setPath(linkParams: any[]|string): void {

            if (typeof linkParams === "string")
                linkParams = [linkParams];

            this.router.navigate(<any[]>linkParams);

        }

    }

}

//Child

@Component({
    selector: 'matches-view',
    providers: [DotaRestDao],
})
@View({
    templateUrl: './components/MatchesView/MatchesView.html',
    directives: [CORE_DIRECTIVES]
})
export class MatchesView {

    public result;

    private dataService: DotaRestDao;

    constructor(dataService: DotaRestDao) {

        this.result = { matches: [] };

        this.dataService = dataService;

        this.dataService.getData({
            baseUrl: DotaRestDao.MATCH_HISTORY_BASE
        }).subscribe(
            res => this.result = res.result,
            err => console.log("something wrongable", err),
            () => console.log('completed')
        );

    }

}

//Template

<table class="table">
              ...
    <button (click)="setPath(match.match_id)">Match Detail Route</button>
</table>
6
  • Can you put an event on your component and let the parent change the route when it gets it? Commented Nov 12, 2015 at 5:13
  • Seems promising but no dice so far. I changed my button to (^click)="setPath(match.match_id)", notice the carat. Did you have something else in mind? Not sure if I'm up to speed on events. Commented Nov 12, 2015 at 13:22
  • Your child component is calling setPath() which is a function you made that only exists on the parent. (The error is telling you that it cant find that function) You will likely need a middleman function to take the event from the child to the parent as I don't think you can call parent functions from child templates. I could be wrong though... Commented Nov 12, 2015 at 17:52
  • Right, I need a way to access a higher-level context. Angular must have an out-of-the-box way to do this, right? Commented Nov 12, 2015 at 23:06
  • 1
    I was thinking <matches-view (selectHero)="changeRouteToHero($event)">, then generate the selectHero event from your component to let the parent handle it and change the route with the changeRouteToHero method. Commented Nov 13, 2015 at 7:56

1 Answer 1

3

In the context of this question, namely calling a parent router, the answer, it turns out, is trivial. See this plunker for details.

The main takeaway is that giving a router to a child component a la

class ChildComponent {

    constructor(router: Router) {

        ...

    }

}

does not create a new router, it merely extends the existing router of the parent component. Thus, the need to a reference to the parent object is obviated. Just call the methods of the childRouter and everything works as expected.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.