Angular 2 - 在父初始化后将数据传递给子组件 [英] Angular 2 - Passing data to Child component after Parent initialisation

查看:33
本文介绍了Angular 2 - 在父初始化后将数据传递给子组件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个父组件,它通过服务从服务器获取数据.我需要将其中一些数据传递给 Child 组件.

我一直在尝试使用通常的 @Input() 传递这些数据,但是正如我所料,我在 Child 组件中获得的数据是 undefined.

示例

父组件

@Component({选择器:'测试父',模板:`<test-child [childData]="data"></test-child>`})导出类 ParentComponent 实现 OnInit {数据:任何;ngOnInit() {this.getData();}获取数据(){//调用服务并获取数据this.testService.getData().subscribe(res => {this.data = res;});}}

子组件

@Component({选择器:'测试子',模板:`<!-- 儿童内容.... -->`})导出类 ChildComponent 实现 OnInit {@Input() 子数据:任意;ngOnInit() {控制台日志(childData);//日志未定义}}

我让示例保持简单,以展示我正在尝试做的事情.我的问题是初始化后是否可以将数据传递给孩子.我不确定,但在这种情况下,双向数据绑定会有所帮助吗?

更多调查

按照发布的答案,我尝试使用 ngOnChanges 生命周期挂钩.我遇到的问题是更新数据时没有触发 ngOnChanges 函数.数据是一个对象,这就是我认为未检测到更改的原因.

子组件中的更新代码

@Component({选择器:'测试子',模板:`<!-- 儿童内容.... -->`})导出类 ChildComponent 实现 OnChanges {@Input() 子数据:任意;ngOnChanges() {控制台日志(childData);//未定义的日志}}

我已经尝试使用来自 Angular 团队的展示 Lifecycle Hooks 的 Live Examples on Plunker 进行测试.在测试中,我更新了 OnChangesComponent 以传递一个对象,如示例中所示,当更新对象时,ngOnChanges 未检测到更改.(这也显示在这个问题中)

https://plnkr.co/edit/KkqwpsYKXmRAx5DK4cnV

似乎 ngDoCheck 可以帮助解决这个问题,但在我看来,从长远来看,它无助于提高性能,因为此 Lifecycle Hook 会检测到每个更改.

我也知道我可以使用 @ViewChild() 来访问子组件并设置我需要的变量,但我不认为对于这个用例很有道理.

发布更多代码以帮助更好地解释

父组件

@Component({选择器:'测试父',模板:`<test-child [childType]="numbers" [childData]="data" (pickItem)="pickNumber($event)"><模板 let-number><span class="number" [class.is-picked]="number.isPicked">{{ number.number }}</span></test-child><test-child [childType]="letters" [childData]="data" (pickItem)="pickLetter($event)"><模板信函><span class="letter" [class.is-picked]="letter.isPicked">{{ letter.displayName }}</span></test-child><button (click)="submitSelections()">提交选择</button>`})导出类 ParentComponent 实现 OnInit {数据:任何;数字数据:任何;字母数据:任何;ngOnInit() {this.getData();}获取数据(){//调用服务并获取游戏选择的数据this.testService.getData().subscribe(res => {this.data = res;setChildData(this.data);});}setChildData(数据:任何){for(let i = 0; i < data.sections.length; i++) {if(data.sections[i].type === '数字') {this.numbersData = data.sections[i];}if(data.sections[i].type === '字母') {this.lettersData = data.sections[i];}}}pickNumber(pickedNumbers: any[]) {this.pickedNumbers = pickedNumbers;}pickLetter(pickedLetters: any[]) {this.pickedLetters = pickedLetters;}提交选择(){//调用服务提交选择}}

子组件

@Component({选择器:'测试子',模板:`<!--儿童内容...显示可供选择的项目列表,点击项目被选中-->`})导出类 ChildComponent 实现 OnInit {@Input() 子数据:任意;@Output() onSelection = new EventEmitter;选择的项目:任何[];//用于点击事件选择项目(项目:任何){this.pickedItems.push(item.number);this.onSelection.emit(this.pickedItems);}}

这或多或少是我拥有的代码.基本上我有一个父组件处理来自子组件的选择,然后我将这些选择提交给服务.我需要将某些数据传递给孩子,因为我试图让孩子以服务期望的格式返回的对象.这将帮助我不要在父组件中创建服务所期望的整个对象.此外,它还会使子进程可重用,因为它会发回服务期望的内容.

更新

我很感激用户仍在发布有关此问题的答案.请注意,上面发布的代码对我有用.我遇到的问题是,在特定模板中,我有一个错字,导致数据 undefined.

希望它被证明是有帮助的:)

解决方案

由于数据在开始时未定义,您可以使用 *ngIf='data'

推迟它

<test-child [childData]="data"></test-child>

或者你可以在你的组件上实现 ControlValueAccessor 并通过 ngModelChange 传递它

<test-child [ngModel]="数据?"(ngModelChange)="data??data=$event:null"></test-child>

I have a parent component which is getting data from a server through a service. I need some of this data to be passed to the Child component.

I've been trying to pass this data with the usual @Input() however as I expected the data I'm getting in the Child component is undefined.

Example

Parent Component

@Component({
    selector: 'test-parent',
    template: `
        <test-child [childData]="data"></test-child>
    `
})

export class ParentComponent implements OnInit {
    data: any;

    ngOnInit() {
        this.getData();
    }

    getData() {
        // calling service and getting data
        this.testService.getData()
            .subscribe(res => {
                this.data = res;
            });
    }
}

Child Component

@Component({
    selector: 'test-child',
    template: `
        <!-- Content for child.... -->
    `
})

export class ChildComponent implements OnInit {
    @Input() childData: any;

    ngOnInit() {
        console.log(childData); // logs undefined
    }
}

I've kept the example simple so as to show what I'm trying to do. My question is whether it's possible to pass data to the child after the initialisation. I'm not sure but would two-way data binding help in this case?

More Investigation

Following the posted answers I've tried using the ngOnChanges lifecycle hook. The issue I'm having is that the ngOnChanges function is not being fired when the data is updated. The data is an object which is why I think the changes are not being detected.

Updated code in the Child Component

@Component({
    selector: 'test-child',
    template: `
        <!-- Content for child.... -->
    `
})

export class ChildComponent implements OnChanges {
    @Input() childData: any;

    ngOnChanges() {
        console.log(childData); // logs undefined
    }
}

I've tried a test with the Live Examples on Plunker from the Angular team showcasing the Lifecycle Hooks. In the test I've updated the OnChangesComponent to pass an object which as can be seen in the example when updating an object the ngOnChanges is not detecting the change. (This is also shown in this question)

https://plnkr.co/edit/KkqwpsYKXmRAx5DK4cnV

Seems that the ngDoCheck could help solve this issue, but it seems to me that it would not help performance in the long run as every change is detected by this Lifecycle Hook.

Also I know that I could probably use the @ViewChild() to access the Child Component and set the variables that I need, but I don't think that for this use-case it makes much sense.

Posting more code to help explain better

Parent Component

@Component({
    selector: 'test-parent',
    template: `
        <test-child [childType]="numbers" [childData]="data" (pickItem)="pickNumber($event)">
            <template let-number>
                <span class="number" [class.is-picked]="number.isPicked">
                    {{ number.number }}
                </span>
            </template>
        </test-child>
        <test-child [childType]="letters" [childData]="data" (pickItem)="pickLetter($event)">
            <template let-letter>
                <span class="letter" [class.is-picked]="letter.isPicked">
                    {{ letter.displayName }}
                </span>
            </template>
        </test-child>
        <button (click)="submitSelections()">Submit Selection</button>
    `
})

export class ParentComponent implements OnInit {
    data: any;
    numbersData: any;
    lettersData: any;

    ngOnInit() {
        this.getData();
    }

    getData() {
        // calling service and getting data for the game selections
        this.testService.getData()
            .subscribe(res => {
                this.data = res;
                setChildData(this.data);
            });
    }

    setChildData(data: any) {
        for(let i = 0; i < data.sections.length; i++) {
            if(data.sections[i].type === 'numbers') {
                this.numbersData = data.sections[i];
            }

            if(data.sections[i].type === 'letters') {
                this.lettersData = data.sections[i];
            }
        }
    }

    pickNumber(pickedNumbers: any[]) {
        this.pickedNumbers = pickedNumbers;
    }

    pickLetter(pickedLetters: any[]) {
        this.pickedLetters = pickedLetters;
    }

    submitSelections() {
        // call service to submit selections
    }
}

Child Component

@Component({
    selector: 'test-child',
    template: `
        <!--
            Content for child...
            Showing list of items for selection, on click item is selected
        -->
    `
})

export class ChildComponent implements OnInit {
    @Input() childData: any;
    @Output() onSelection = new EventEmitter<Selection>;

    pickedItems: any[];

    // used for click event
    pickItem(item: any) {
        this.pickedItems.push(item.number);

        this.onSelection.emit(this.pickedItems);
    }
}

That's more or less the code that I have. Basically I have a parent that handles selections from child components and then I submit these selections to the service. I need to pass certain data to the child because I'm trying to have the object that the child returns in the format that the service is expecting. This would help me not to create the whole object expected by the service in the parent component. Also it would make the child reuseable in the sense that it sends back what the service expects.

Update

I appreciate that users are still posting answers on this question. Note that the code that has been posted above worked for me. The issue I had was that in a particular template I had a typo which caused for the data to be undefined.

Hope that it's proving to be helpful :)

解决方案

Since data is undefined at start, you can postpone it with *ngIf='data'

<div *ngIf='data'>
   <test-child [childData]="data"></test-child>
</div>

Or you can implement ControlValueAccessor on your component and pass it by ngModel with ngModelChange

<test-child [ngModel]="data?" (ngModelChange)="data? ? data= $event : null"></test-child>

这篇关于Angular 2 - 在父初始化后将数据传递给子组件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆