Unpopular features of Angular

Pankaj P. Parkar

Principal Application Devloper

  • Ex- Microsoft MVP (2015-22)

  • Angular GDE

About Me!

pankajparkar

  • @ngx-lib/multiselect - OSS library
  • FREE Angular Course
  • #devwhorun 🏃‍♂️ - 100km / month

Route based dialogs

Auxiliary Routes 🚀

export const routes: Routes = [
  { path: 'dashboard', component: DashboardComponent },
  { 
    path: 'login', 
    component: LoginComponent, 
    outlet: 'modal'
  },
  { 
    path: 'details',
    component: DetailsComponent, 
    outlet: 'modal'
  },
  { path: '**', redirectTo: 'dashboard' },
];
<div class="main-container">
  <uf-navbar></uf-navbar>
  <router-outlet></router-outlet>
  <router-outlet name="modal"></router-outlet>
</div>
[routerLink]="[{
  outlets: { modal: ['login']}
}]"

Route based dialogs

Auxiliary Routes 🚀

@Component({
  selector: 'uf-login',
  ...
})
export class LoginComponent {
  router = inject(Router);
  ref = inject(MatDialog)
    .open(LoginDialog)
    .afterClosed()
    .subscribe(() => {
      this.router.navigate([{ 
        outlets: { modal: null } 
      }])
    });
}
@Component({
  standalone: true,
  imports: [
    ...
  ],
  template: `
    ...
  `
})
export class LoginDialog {
  ...
}

Access parent component from child component

@Component({
  selector: 'uf-child-to-parent-access',
  ...,
  providers: [CardsService],
  template: `
    <mat-card class="example-card">
      <mat-card-header>
        <mat-card-title>{{card.title}}</mat-card-title>
      </mat-card-header>
      <mat-card-actions>
        <child-component></child-component>
      </mat-card-actions>
    </mat-card>
  `,
})
export class ParentComponent {
  public card = inject(CardsService).getCardDetails();
}
@Component({
  selector: 'child-component',
  imports: [
    ...
  ],
  template: `
    somewhere in the footer
  `,
})
export class ChildComponent {
  // Needs to read parent cmp info
}

Access parent component properties from child component

export class ChildComponent {
  @Host() @Optional()
  protected parent = inject(ParentComponent);

  ngOnInit() {
    console.log(this.parent);
  }
}

DI + @Host()

export class ChildComponent {
  protected parent = inject(ParentComponent);

  ngOnInit() {
    console.log(this.parent);
  }
}

DI Injection

Extend existing/3rd party directives

Directive  🚀

<mat-paginator
  (page)="handlePageEvent($event)"
  [length]="length"
  [pageIndex]="pageIndex"
  [pageSize]="pageSize"
  [showFirstLastButtons]="true"
  [pageSizeOptions]="[5,10,25]"
  aria-label="Select page">
</mat-paginator>

Extend existing/3rd party directives

Directive  🚀

@Directive({
  selector: 'mat-paginator',
  standalone: true,
})
export class FancyPaginatorDirective {
  paginator = inject(MatPaginator);
  el = inject(ElementRef);

  @HostBinding('attr.aria-label')
  ariaLabel = 'Select page';

  ngOnInit() {
    this.paginator.showFirstLastButtons = true;
    this.paginator.pageSizeOptions = [5, 10, 25];
  }
}
@Component({
  selector: 'uf-extend-third-party',
  standalone: true,
  imports: [
    MatPaginatorModule,
    FancyPaginatorDirective,
  ],
})
export class ExtendThirdParty {
}

Access template variable as component instance

Utilize the power of exportAs in directive/component

<div class="button-row">
  <button #button mat-button (click)="testClick(button)">
    Basic
  </button>
</div>

Access template variable as component instance

Utilize the power of exportAs in directive/component

@Directive({
  selector: '[ufUseRef]',
  standalone: true
})
export class UseRefDirective {
  dom = inject(ElementRef).nativeElement;
}
<button 
  mat-button
  ufUseRef
  #button="ufUseRef" 
  (click)="testClick(button)">
  Basic
</button>

ngDestroy hook in Angular service

@Injectable()
export class LogService {
  interval: any;
  count = 0;

  constructor() {
    console.log('constructor: logging starting...');
    this.interval = setInterval(() => {
      console.log(this.count++);
    }, 1000);
  }

  ngOnDestroy() {
    console.log('ngOnDestroy: cleaning up...');
    clearInterval(this.interval);
  }
}

@pankajparkar

www.pankajparkar.com

Say Hi 👋

@pankajparkar

@pankajparkar

@pankajparkar

@pankajparkar

Reference

  • https://timdeschryver.dev/blog/use-angular-directives-to-extend-components-that-you-dont-own
  •  

Unpopular features of Angular

By Pankaj Parkar

Unpopular features of Angular

Unpopular features of Angular

  • 198