Nikolay Stefanov
Nikolay Stefanov

Reputation: 83

How to dynamic load fontawesome icon by iconName and prefix?

I investigated the problem for dynamic load of fontawesome icon by iconName. But the code is not working. What is the reason? What is the best practice? And why I need the call for ngOnChanges() in the directive ngOnInit() hook? The error I get in the browser is "FontAwesome: Could not find icon. It looks like you've provided a null or undefined icon object to this component."

import { AppComponent } from './app.component';
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
import { library, dom } from '@fortawesome/fontawesome-svg-core';
import { fas,faCheck, faCalendar, faTimes } from '@fortawesome/free-solid-svg-icons';
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { IconDirective } from './icon.directive';

@NgModule({
  declarations: [AppComponent, IconDirective],
  imports: [BrowserModule, FontAwesomeModule],
  providers: [],
  bootstrap: [AppComponent],
  entryComponents: [FaIconComponent],
})
export class AppModule {
  constructor() {
    library.add(fas,faCheck, faCalendar, faTimes);
    dom.watch();
  }
}
import { Component } from '@angular/core';

@Component({
    selector: 'app-root',
    template: '<div iconDirective></div>'
})
export class AppComponent {
    constructor() { }
}
import { Directive, OnInit, ViewContainerRef, ComponentFactoryResolver }
from '@angular/core';
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
import { faCheck, faCalendar, faTimes } from '@fortawesome/free-solid-svg-icons';
import { icon } from '@fortawesome/fontawesome-svg-core';

@Directive({
  selector: '[iconDirective]'
})
export class IconDirective{
   constructor(      
      public viewContainerRef: ViewContainerRef,
      private componentFactoryResolver: ComponentFactoryResolver) {
    }
    ngOnInit() {
      const componentFactory =
          this.componentFactoryResolver.resolveComponentFactory(FaIconComponent);
      const componentRef =
          this.viewContainerRef.createComponent(componentFactory);
      (<FaIconComponent>componentRef.instance).icon =
           icon({iconName: 'times', prefix: 'fas'});
      // (<FaIconComponent>componentRef.instance).iconProp = faCheck; //works
      (<FaIconComponent>componentRef.instance).ngOnChanges({});
    }
}

Upvotes: 3

Views: 4149

Answers (1)

Yaroslav Admin
Yaroslav Admin

Reputation: 14535

Since the 0.5.0 release angular-fontawesome has a better support for rendering icon component dynamically. Check out the official documentation:

@Component({
  selector: 'fa-host',
  template: '<ng-container #host></ng-container>'
})
class HostComponent {
  @ViewChild('host', {static: true, read: ViewContainerRef}) container: ViewContainerRef;

  constructor(private cfr: ComponentFactoryResolver) {
  }

  createIcon() {
    const factory = this.cfr.resolveComponentFactory(FaIconComponent);
    const componentRef = this.container.createComponent(factory);
    componentRef.instance.icon = faUser;
    // Note that FaIconComponent.render() should be called to update the
    // rendered SVG after setting/updating component inputs.
    componentRef.instance.render();
  }
}

What is the reason? The error I get in the browser is "FontAwesome: Could not find icon. It looks like you've provided a null or undefined icon object to this component."

Because you should have set iconProp input property, not icon property, which was errornously exposed on the component. Note that this is no longer the case in >0.5.0 (see example above).

What is the best practice?

See example above.

And why I need the call for ngOnChanges() in the directive ngOnInit() hook?

Because icon rendering is triggered by a call to ngOnChanges hook, which is performed by the Angular framework when you add component in the template. When creating a component dynamically Angular does not call this hook, so you need to do it manually. Note that in >0.5.0 there is a dedicated method, which triggers rendering without relying on this implementation detail - FaIconComponent.render().

Upvotes: 2

Related Questions