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

Pass route param to child component as input in Angular 2

我有一个 parent 组件,它从路由参数中获取一个 id 值。我想将它传递给 child 组件,所以我通过 child 组件上的 Input() 装饰器来实现。但是,我无法将路由参数值传递给 child。如果我 hard-code 一个值并将其传递给 child 它会起作用,所以我相信绑定和 child 组件逻辑没问题;我认为这只是 how/where 我正在动态设置值的问题。

这是完整的 parent 组件,其中包含一些注释:

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;
}

...这是 child 组件:

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
            );
    }
}

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

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

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

我创建了小型库(目前仅适用于 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 网站上找到它以及文档)