I'm building an Angular application and need to access a property of Component 1 in Component 3. The relationship between component 1 and component 3 is grandparent-grandchild.
I've successfully implemented communication between parent/child components directly (ie from component 1 to component 2 and from component 2 to component 3 (note that component 3 is the child of component 2 and component 2 is the child of component 1). I only need one-way communication (ie accessing properties from (grand)parent-components in the child-component).
Below you can see the structure of my application. I also make use of shared services.
Component 1.ts
import { Component, OnInit } from '@angular/core'
import { StrategyService } from './shared/strategy.service'
@Component({
selector: 'strategies-list',
templateUrl: './strategies-list.component.html'
})
export class StrategiesListComponent implements OnInit {
strategies:any[]
constructor(private strategyService: StrategyService) {
}
ngOnInit() {
this.strategies = this.strategyService.getStrategies()
}
}
Component 1.html
<div>
<h1>Strategies</h1>
<hr/>
<strategy-thumbnail *ngFor = "let strategy of strategies" [strategy] = "strategy"> </strategy-thumbnail>
</div>
Component 2.ts
import { StrategyService } from './shared/strategy.service'
@Component ({
selector:'strategy-thumbnail',
templateUrl:'./strategy-thumbnail.component.html',
styles: [`
.pad-left { margin-left: 10px; }
.well div { color: #bbb; }
`]
})
export class StrategyThumbnailComponent implements OnInit {
@Input() strategy:any
psets:any
constructor(private strategyService: StrategyService) {
}
ngOnInit() {
this.psets =this.strategyService.getParameterSets(this.strategy.Name)
}
}
Component 2.html
<div class="well">
{{strategy?.Name}}
<param-set *ngFor = "let pset of psets" [pset] = "pset"> </param-set>
</div>
Component 3.ts
import { Component, Input, OnInit } from '@angular/core'
import { StrategyService } from '../strategies/shared/strategy.service'
@Component ({
selector:'param-set',
templateUrl:'./param-set.component.html'
})
export class ParamSetComponent {
@Input() pset: any
@Input() strategy: any
returns: any
constructor(private strategyService: StrategyService) {
}
ngOnInit() {
this.returns = this.strategyService.getReturns(***SomeStrategyName***,this.pset.Name)
}
}
Component 3.html
<div> {{pset?.Name}} </div>
<return-vector *ngFor = "let return of returns" [return] = "return"> </return-vector>
Component 4.ts
import { Component, Input } from '@angular/core'
@Component ({
selector:'return-vector',
templateUrl:'./return-vector.component.html'
})
export class ReturnVectorComponent {
@Input() strategy:any
@Input() pset: any
@Input() return: any
}
Component 4.html
<div>Period: {{return?.period}}, Return: {{return?.return}}</div>
strategy.service.ts
import { Injectable } from '@angular/core'
@Injectable()
export class StrategyService {
getStrategies() {
return STRATEGIES
}
getStrategy(Name:string) {
return this.getStrategies().find(strat => strat.Name === Name)
}
getParameterSets (Name: string) {
return this.getStrategy(Name).PSETS
}
getParameterSet (StrategyName, PSetName) {
return this.getParameterSets(StrategyName).find(pset => pset.Name === PSetName)
}
getReturns (StrategyName, PSetName) {
return this.getParameterSet(StrategyName, PSetName).Returns
}
getReturn(StrategyName, PSetName, Period) {
return this.getReturns(StrategyName, PSetName).find(returnperiod => returnperiod.period === Period)
}
}
const STRATEGIES = [
{ "Name": "SomeStrategyName1", "PSETS: [{"Name":"SomePSetName1", "Returns": [{ "period": "someperiod1", "return" : somenumber1}, {"period": "someperiod2", "return" : somenumber2}]}, {"Name":"SomePSetName2", "Returns": [{ "period": "someperiod3", "return" : somenumber3}, {"period": "someperiod4", "return" : somenumber4}]}]},
{ "Name": "SomeStrategyName2", "PSETS: [{"Name":"SomePSetName3", "Returns": [{ "period": "someperiod5", "return" : somenumber5}, {"period": "someperiod6", "return" : somenumber6}]}, {"Name":"SomePSetName4", "Returns": [{ "period": "someperiod3", "return" : somenumber3}, {"period": "someperiod4", "return" : somenumber4}]}]},
...
{ "Name": "SomeStrategyNameK", "PSETS: [{"Name":"SomePSetName3", "Returns": [{ "period": "someperiod5", "return" : somenumber5}, {"period": "someperiod6", "return" : somenumber6}]}, {"Name":"SomePSetName4", "Returns": [{ "period": "someperiod3", "return" : somenumber3}, {"period": "someperiod4", "return" : somenumber4}]}]}]
In the code above, everything works as expected apart from one thing: in component 3.ts I want to access some specific return set. If I input some specific strategy name (eg "SomeStrategyName1"), my code works. But I want this strategy name to be specific to the strategies I'm looping through.
I've tried replacing "SomeStrategyName1" with this.strategy.Name since I've used the input parameter twice (once in component 3 and once in component 2). In component 2, this works: I can successfully access the Name property of this.strategy when calling the getParameterSets function in the ts-file.
In Component 3 however, this does not work. I get a TypeError: Cannot read property 'Name' of undefined at ParamSetComponent.ngOnInit.
You need to pass strategy
in Component 2 Template to param-set
component as it expects one:
<div class="well">
{{strategy?.Name}}
<param-set
*ngFor="let pset of psets"
[pset]="pset"
[strategy]="strategy">
</param-set>
</div>
You'll also have to do the same for Component 3 and so on...
<div> {{pset?.Name}} </div>
<return-vector
*ngFor="let return of returns"
[pset]="pset"
[strategy]="strategy"
[return]="return">
</return-vector>
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.