I am implementing event handling in a component named StructureWindowComponent and also have an override for it in LeggerStructureWindowComponent..
In the base class (StructureWindowComponent) the event handling for blur event is as follows:
symbolCellLostFocus = (symbolField : MatInput, $index: number) =>{
console.log("base class symbol cell lost focus");
//implementation...
}
I am implementing event handling in a component named StructureWindowComponent and also have an override for it in LeggerStructureWindowComponent..
In the base class (StructureWindowComponent) the event handling for blur event is as follows:
symbolCellLostFocus = (symbolField : MatInput, $index: number) =>{
console.log("base class symbol cell lost focus");
//implementation...
}
In the derived class LeggerStructureWindowComponent, I am calling this method using super like this...
symbolCellLostFocus = (symbolField : MatInput, $index: number) =>{
console.log("derived class symbol lost focus");
super.symbolCellLostFocus(symbolField, $index);
}
I get the error in the console: ERROR TypeError: (intermediate value).symbolCellLostFocus is not a function
Not sure what is wrong here.. can someone please advice?
Share Improve this question edited Oct 23, 2020 at 10:57 R. Richards 25.2k10 gold badges66 silver badges65 bronze badges asked Oct 23, 2020 at 10:46 Teja ReddyTeja Reddy 1011 silver badge4 bronze badges 2- I think you might need to add a semicolon behind the closing curly braces. Btw., is there a reason why you don't make these named functions? – Gunnar B. Commented Oct 23, 2020 at 11:26
- Gunnar, I have just shown small part of the code. There is more logic after that. Thanks for the suggestion though – Teja Reddy Commented Oct 23, 2020 at 14:00
1 Answer
Reset to default 20This is a tricky one, but it has to do with the use of arrow functions syntax in classes, and the prototype chain. It is not related to Angular specifically.
Basically if you want to fix your issue, you need to replace a = () => { ... }
with a() { ... }
:
symbolCellLostFocus(symbolField : MatInput, $index: number) {
console.log("base class symbol cell lost focus");
//implementation...
}
symbolCellLostFocus(symbolField : MatInput, $index: number) {
console.log("derived class symbol lost focus");
super.symbolCellLostFocus(symbolField, $index);
}
Now for the explanation, if you write the following snippet:
class A {
name = 'A'
sayHello = () => {
console.log('Hello from A')
}
}
class B extends A {
name = 'B'
sayHello = () => {
console.log('Hello from B')
super.sayHello()
}
}
It is transformed into this JavaScript snippet:
class A {
constructor() {
this.name = 'A';
this.sayHello = () => {
console.log('Hello from A');
};
}
}
class B extends A {
constructor() {
super(...arguments);
this.name = 'B';
this.sayHello = () => {
console.log('Hello from B');
super.sayHello();
};
}
}
As you can see, the methods are defined in the constructor, for each instance created by the constructors. This means that the method sayHello
from A
is not available for B
, because sayHello
is not available in the prototype of B
(which is A
), it is only available for each instance of A
. This can be confusing, I highly recommend learning about prototype inheritance in JavaScript!
Classes, introduced in ES2015, are just syntactic sugar for prototype inheritance in JavaScript. The class
, constructor
, super
, etc. keywords only abstract the syntax needed to write prototype chains. Essentially, it's the way to achieve composition and inheritance in JavaScript, a very powerful concept.
Anyway, when you write super.X()
here, the JavaScript engine is trying to access the X
method on the prototype, which doesn't exist. You end up with Object.getPrototypeOf(this).undefined()
, and undefined
is indeed not a function, so you get a TypeError: (intermediate value).sayHello is not a function
runtime error.
Here's an example to illustrate what I said: TS playground.