将路径参数传递给子组件作为Angular 2中的输入

时间:2016-05-15 09:38:58

标签: typescript angular angular2-template

我有一个父组件,它从路由参数中获取一个id值。我想将它传递给子组件,所以我通过子组件上的Input()装饰器来做这件事。但是,我无法将路线参数值传递给孩子。如果我对一个值进行硬编码并将其传递给它可以正常工作,那么我相信绑定和子组件逻辑是可以的;我认为这只是我如何/在哪里动态设置值的问题。

这是包含一些注释的完整父组件:

import { Component }                                                from '@angular/core';
import { HTTP_PROVIDERS }                                           from '@angular/http';
import { provide }                                                  from '@angular/core';
import { Routes, Router, RouterUrlSerializer, ROUTER_DIRECTIVES }   from '@angular/router';
import { Location }                                                 from '@angular/common';
import { XHRBackend }                                               from '@angular/http';

import { ContentNode }                                              from './content-node';
import { ContentTreeComponent }                                     from './content-tree.component';
import { ContentDashboardComponent }                                from './content-dashboard.component';
import { ContentEditComponent }                                     from './content-edit.component';

import { ContentService }                                           from '../services/content.service';
import { InitService }                                              from '../services/init.service';
import { RouteNames }                                               from '../services/route-names.service';

@Component({
    selector: 'my-dashboard',
    template: `
        <div class="tree-panel-container">
            <div class="tree-panel-content">
                <content-tree [startNodeId]="startNodeIdContent" [currentNodeId]="currentNodeId"></content-tree>
            </div>
        </div>
        <router-outlet></router-outlet>
    `,
    directives: [
        ContentTreeComponent, 
        ContentDashboardComponent, 
        ROUTER_DIRECTIVES
    ],
    providers: [
        HTTP_PROVIDERS
    ]
})
@Routes([
    { path:'/',    component: ContentDashboardComponent },
    { path:'/:id', component: ContentEditComponent }
])
export class ContentComponent {

    _currentNodeId: number;

    constructor(private router:Router, private routeSerializer:RouterUrlSerializer, private location:Location) {
        router.changes.first().subscribe(() => {
            let urlTree = this.routeSerializer.parse(location.path());
            let urlSegment = urlTree.children(urlTree.children(urlTree.root)[0])[0];
            if(urlSegment != undefined){
                let id = urlSegment.segment;
                this._currentNodeId = id;
                console.log('_currentNodeId', this._currentNodeId); // This works - it logs the correct id from the route param
            }
        });
    }

    startNodeIdContent = InitService.startNodeIdContent;
    currentNodeId = this._currentNodeId; // This doesn't work - it just results in 'undefined' in the child component

    // The following line works; it passes 123 to the child component, so I know the binding and the child input is set up correctly:
    // currentNodeId = 123;
}

...这里是子组件:

import { Component, Input, OnInit }         from '@angular/core';
import { Router, RouteSegment, RouteTree }  from '@angular/router';

import { ContentNode }                      from './content-node';
import { ContentService }                   from '../services/content.service';


@Component({
    selector: 'content-tree',
    directives: [ContentTreeComponent],
    template: `
        <ol class="tree">
            <li *ngFor="let contentNode of contentNodes" class="tree__branch" [ngClass]="{'tree__branch--has-children': contentNode.HasChildren}">
                <a *ngIf="contentNode.HasChildren" (click)="contentNode.toggle=!contentNode.toggle" class="tree__branch__toggle">
                    {{ !!contentNode.toggle ? '-' : '+' }}
                </a> 
                <a class="tree__branch__link" (click)="onSelect(contentNode)">{{ contentNode.Name }}</a>
                <content-tree *ngIf="contentNode.toggle" [startNodeId]="contentNode.Id"></content-tree>
            </li>
        </ol>
        <div class="error" *ngIf="errorMessage">{{errorMessage}}</div>
        <p>{{test}}</p>
    `
})
export class ContentTreeComponent implements OnInit {

    constructor(
        private _contentService: ContentService,
        private _router: Router,
        private _currSegment: RouteSegment
    ) { }

    errorMessage: string;

    @Input('startNodeId')
    private _startNodeId: number;

    @Input('currentNodeId')
    private _currentNodeId: number;

    contentNodes: ContentNode[];

    ngOnInit() { 
        this.getContentNodes();

        console.log('_startNodeId = ' + this._startNodeId);
        console.log('_currentNodeId = ' + this._currentNodeId);
    }

    onSelect(contentNode: ContentNode) {
        this._router.navigate([`./${contentNode.Id}`], this._currSegment);
    }

    getContentNodes() {
        this._contentService.getContentNodes(this._startNodeId)
            .subscribe(
                contentNodes => this.contentNodes = contentNodes,
                error =>  this.errorMessage = <any>error
            );
    }
}

3 个答案:

答案 0 :(得分:1)

路由器使用ViewContainerRef.createComponent添加组件。对于以这种方式添加的组件,不支持@Input()@Output()

在不支持输入和输出的组件之间共享数据的常用方法是共享服务。有关详细信息,请参阅https://angular.io/docs/ts/latest/cookbook/component-communication.html

答案 1 :(得分:1)

当我在路由到子组件时尝试传递任何值时遇到了同样的问题,所以它似乎不起作用,因为路由器将ViewContainerRef.createComponent添加到那些子组件,因此@Input和@Output都不会工作, 我创建了SharedService并在父组件中启动它并在我需要的地方注入了这个服务。希望它也能帮助你

答案 2 :(得分:0)

我创建了一个小型库(目前仅适用于angular 9,我可能可以添加对较早版本的支持,但还会附带一些其他代码)

npm install --save ngx-route-params-input

您可以在此处查看它的运行情况: https://stackblitz.com/edit/angular-v8hdug?embed=1&file=src/app/user/user-routing.module.ts

它正在以另一种方式工作:

// import component (you will also need to provide 
// NgxRouteParamsInputModule to your angular module imports)
import { NgxRouteParamsInputComponent } from "ngx-route-params-input";

const routes: Routes = [
  {
    path: ":userId",
    // Change YourComponent to NgxRouteParamsInputComponent:
    component: NgxRouteParamsInputComponent,
    data: {
      // Provide YourComponent in route data
      component: YourComponent,
      // Provide params you want to pass from URL to component
      routeParams: {
        userId: "userId"
      },
      // you can also provide query params
      queryParams: {
        content: "content"
      }
    }
  }
];

如果对此包有任何问题或评论,请随时在GitHub上添加评论/功能请求等(您可以在npm网站上找到它和文档)