I recently stuck with an issue and want to share the solution with you.
I needed to create a component that uses a method of any other component that uses it.
you may think we can pass the method as a property to the child component, it is a straightforward solution but introduces a new issue
the component looks like:
<my-component [transform]="transform"></my-component>
and the method looks like
@component({ /* ... */ })
class ParentComponent{
prop = 1
transform(data){
// sure this.prop has a value
return {...data, prop: this.prop}
}
}
easy, right?
no ..
if you investigated the returned value you will find it looks like
@component({ /* ... */})
class MyComponent{
@Input() transform: (data: Data) => Data;
ngOnInit(){
console.log(data); // {x: 1}
let newData = this.transform?.(data) || data;
console.log(newData); // {x:1, prop: undefined}
wait … what?!! undefined!!
why newData.prop
here is undefined, should it have a value?!!
no other method changed its value.
let’s debug our parent class by logging the value of this.prop,
the good news it always has a fixed value of “1”.
the bad news, it always undefined
inside transform()
, even it has a value everywhere and inside all methods .. except transform()
why?!!
simply, because it is executed inside another context i.e. MyComponent
therefore this
here refers to MyComponent
instead of ParentComponent
now we can easily offer a solution
the solution
we can bind this
to ParentComponent
, or the most simple solution is to use the arrow function, so, this
here refers to the outer context i.e ParentComponent
which exactly we need.
class ParentComponent{
this.prop=1;
// now `this` refers to ParentComponent,
// and this.prop has the intersted value
transform: (data)=>({...data, prop: this.prop})
}