0

what am i missing here? This is a simplified example of creating an Angular 18 base component and a heir component extending it. Both are standalone. All seems fine in that the heir component sees the base components properties and methods in this. override is required on base methods and properties. Changes to the variables done in either base or heir show up. My problem is the html in base doesn't seem to recognize any changes in the variables. Change the variables in either base or heir and the heir html responds. Not what I expected.

I create a base component QueryBaseComponent

name:string='nancy;

changeName(newName:string){
    this.name = newName;
    console.log(this.name);//shows liberace
}

onClick(event:any){
//always fires even if it is override in heir component
    console.log('base');
}

html

<label>{{name}}</label>  //always shows initial value of nancy, doesn't change
<button (click)="onClick($event)">hit me</button>
<ng-content select="[position=bottom]"></ng-content>

i extend the base component

export class QueryTextComponent extends QueryBaseComponent implements AfterViewInit

ngAfterViewInit(){
    this.changeName('liberace');
}

override onClick(event:any){
//never gets hit
    console.log('heir');
}

html

<app-query-base>
    <div position="bottom">
        <label>{{name}}</label> //shows nancy and then liberace
    </div>
</app-query-base>
    
 
1
  • Please show what's inside @Component decorators Commented Oct 18, 2024 at 13:01

1 Answer 1

0

You need to notice, that when you use content projection. The methods inside the content actually still have the original scope that it was declared on. So the HTML inside base component will always call the base component methods.

Since you declared the HTML content(stuff inside app-query-base on QueryTextComponent, it will always have access to the methods of QueryTextComponent.

The best solution is to simply move the button inside the QueryTextComponent so that the chick will call the override method instead of the base method.

<app-query-base>
  <div position="bottom">
    <button (click)="onClick($event)">hit me</button>
    <div><label>{{name}}</label> </div>
  </div>
</app-query-base>

Full Code:

import { Component, AfterViewInit } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';

@Component({
  selector: 'app-query-base',
  standalone: true,
  template: `
    <label>{{name}}</label>  
    <ng-content select="[position=bottom]"></ng-content>
  `,
})
export class QueryBaseComponent {
  name: string = 'nancy';

  changeName(newName: string) {
    this.name = newName;
    console.log(this.name);
  }

  onClick(event: any) {
    console.log('base');
  }
}

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [QueryBaseComponent],
  template: `
    <app-query-base>
      <div position="bottom">
        <button (click)="onClick($event)">hit me</button>
        <div><label>{{name}}</label> </div>
      </div>
    </app-query-base>
  `,
})
export class App extends QueryBaseComponent implements AfterViewInit {
  ngAfterViewInit() {
    this.changeName('liberace');
  }

  override onClick(event: any) {
    console.log('heir');
  }
}

bootstrapApplication(App);

Stackblitz Demo

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for responding so quickly and thoroughly. so although the base provides variables and methods they all belong in the heir's scope and the base has no access to the changes. I guess that is understandable but highly disappointing. Inheriting from the base is useful in that it makes variables and functions available that several of my components need but any html will not react to data changes. Major bummer. So why even allow extending components if all you get is class non visual action . May as well use a plain old class.
@FairSite2C Actually, the button calling can be achieved using @Output which emits a event, which the parent component can receive and trigger the click event, maybe you just need to get used to the way angular behaves, but I guarantee you, it can do anything you want to. Inheritance is good for sharing properties and methods. If you want to call methods in another component you should look at @Output and event binding (eventEmitter)="click($event)" angular.dev website is best with its tutorials

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.