Angular 2 - 在父组件初始化后将数据传递给子组件
Angular 2 - 在父组件初始化后将数据传递给子组件
我有一个父组件,通过服务从服务器获取数据。我需要将其中的一些数据传递给子组件。
我一直试图用通常的@Input()
来传递这些数据,但是正如我所预料的,我在子组件中得到的数据是undefined
。
示例
父组件
@Component({ selector: 'test-parent', template: `` }) export class ParentComponent implements OnInit { data: any; ngOnInit() { this.getData(); } getData() { // 调用服务并获取数据 this.testService.getData() .subscribe(res => { this.data = res; }); } }
子组件
@Component({ selector: 'test-child', template: ` ` }) export class ChildComponent implements OnInit { @Input() childData: any; ngOnInit() { console.log(childData); // 输出undefined } }
我保持示例简单,以展示我的意图。我的问题是是否可能在初始化之后将数据传递给子组件。我不确定,但是双向数据绑定是否有助于解决这个问题?
更多调查
根据已发布的答案,我尝试使用ngOnChanges
生命周期钩子。我遇到的问题是当数据更新时,ngOnChanges
函数不会触发。我认为这是因为数据是一个对象,所以改变没有被检测到。
子组件中更新后的代码
@Component({ selector: 'test-child', template: ` ` }) export class ChildComponent implements OnChanges { @Input() childData: any; ngOnChanges() { console.log(childData); // 输出undefined } }
我尝试了一下Angular团队展示生命周期钩子的Plunker上的实时例子。在测试中,我更新了OnChangesComponent以传递一个对象,正如例子中所示,当更新一个对象时,ngOnChanges没有检测到更改。(这也在这个问题中显示出来)
https://plnkr.co/edit/KkqwpsYKXmRAx5DK4cnV
似乎ngDoCheck
可以帮助解决这个问题,但我认为从长远来看,这不会提高性能,因为每次更改都会被这个生命周期钩子检测到。
我也知道我可能可以使用@ViewChild()
来访问子组件并设置我需要的变量,但是我认为对于这个用例来说,这并没有太多意义。
发布更多代码以更好地解释
父组件
@Component({ selector: 'test-parent', template: `{{ number.number }} {{ letter.displayName }} ` }) export class ParentComponent implements OnInit { data: any; numbersData: any; lettersData: any; ngOnInit() { this.getData(); } getData() { // 调用服务并获取游戏选择的数据 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() { // 调用服务提交选择 } }
子组件
@Component({ selector: 'test-child', template: ` ` }) export class ChildComponent implements OnInit { @Input() childData: any; @Output() onSelection = new EventEmitter; pickedItems: any[]; // 用于点击事件 pickItem(item: any) { this.pickedItems.push(item.number); this.onSelection.emit(this.pickedItems); } }
这大致是我拥有的代码。基本上,我有一个父组件处理子组件的选择,然后我将这些选择提交给服务。我需要将某些数据传递给子组件,因为我试图使子组件返回的对象格式符合服务的期望。这样做可以帮助我避免在父组件中创建服务所期望的整个对象。此外,它使得子组件在发送回服务所期望的内容方面具有重用性。
更新
我很感激用户仍然在这个问题上发布答案。请注意,上面发布的代码对我有用。我遇到的问题是在一个特定的模板中有一个拼写错误,导致数据为undefined
。
希望它能对你有所帮助 🙂
问题的原因是在父组件(Parent component)初始化之后将数据传递给子组件(Child component)时,子组件无法正确获取到数据。解决方法是使用ngOnChanges方法来获取数据。
ngOnChanges是Angular的生命周期钩子方法之一,在组件或指令的输入属性(input properties)发生变化时被调用。
ngOnChanges示例代码如下:
ngOnChanges() { if(!!childData){ console.log(childData); } }
ngOnChanges方法只有在整个对象被更改时才会触发,如果只想更新绑定对象的属性而不是整个对象,有两种方法可以解决:
1. 直接在模板中绑定属性,确保使用?来处理可能为空的情况,例如:{{childData?.propertyName}}
2. 创建一个依赖于childData对象的get属性,例如:
get prop2(){ return this.childData.prop2; }
以下是完整示例代码:
import { Component, Input } from '/core'; @Component({ selector: 'my-app', template: `Hello {{name}}
` }) export class AppComponent { name = 'Angular'; childData = {}; constructor(){ // 2秒后设置childData setTimeout(() => { this.childData = { prop1 : 'value of prop1', prop2 : 'value of prop2' } }, 2000) } } @Component({ selector: 'child-component', template: ` prop1 : {{childData?.prop1}} prop2 : {{prop2}} ` }) export class ChildComponent { @Input() childData: {prop1: string, prop2: string}; get prop2(){ return this.childData.prop2; } }
以上代码的运行结果可以在Plunker上查看:[Plunker](http://plnkr.co/edit/DxNfkDdg2ClNVzI6HMLf?p=preview)
希望这可以帮到你!感谢你的回答,它似乎指导了我正确的方向。我现在唯一遇到的问题是,如果数据是一个"简单的"字符串,ngOnChanges会检测到变化,但如果是一个对象,出于某种原因它会保持undefined。
更新答案:
再次感谢你的帮助...我刚刚发现问题所在。在模板变量中有一个拼写错误,所以它总是undefined。之前没有意识到!现在看起来好像可以了,显然我不需要任何ngOnChanges或getter来处理对象...现在看起来没问题了。
问题出现的原因是由于在父组件初始化时,数据是未定义的。解决方法是使用*ngIf='data'来延迟加载数据,或者在组件上实现ControlValueAccessor并使用ngModel传递数据。
首先,我们可以使用*ngIf='data'来延迟加载数据。这意味着只有当data有值时,才会渲染子组件。代码如下:
另一种解决方法是在组件上实现ControlValueAccessor,并使用ngModel和ngModelChange来传递数据。代码如下:
*ngIf='data'可能并不是最佳的解决方法。对于我来说,它并没有起作用。相反,ngOnChanges是一个有效的解决方法。通过在子组件中实现ngOnChanges生命周期钩子函数,我们可以在父组件传递数据给子组件时进行相应的操作。