I am constructing an Angular application and facing the challenge of accessing a property of Component 1 within Component 3. In this scenario, the relationship is described as grandparent-grandchild.
Successfully establishing communication between parent/child components directly, such as from Component 1 to Component 2 and from Component 2 to Component 3 (Component 3 being the child of Component 2 and Component 2 the child of Component 1). The requirement is for one-way communication, specifically accessing properties from (grand)parent-components in the child-component.
Take a look at the application structure provided below, showcasing the usage 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}]}]}]
Within the provided code, all functionalities are working correctly except one: in Component 3.ts, there is a need to access a specific return set. While the code functions when inputting a specific strategy name (e.g., "SomeStrategyName1"), the goal is for this strategy name to be distinct to the strategies being looped through.
Attempts were made to replace "SomeStrategyName1" with this.strategy.Name since the input parameter was used twice (once in Component 3 and once in Component 2). This approach worked in Component 2, enabling successful access to the Name property of this.strategy when invoking the getParameterSets function in the ts file.
However, Component 3 did not yield the same outcome. An error was encountered: TypeError: Cannot read property 'Name' of undefined at ParamSetComponent.ngOnInit.