I have an angular 11
project in development that uses angular-fontawesome
and angular material icon
. It contains a 'problem' model with an optional 'icon' property: string;'. The data constant "problem " contains an arrangement of several "problem " in whose property "icon": is a string, for example "donate", that refers to the "faDonate" icon imported from the fontawesome
library.
My code:
comun.module.ts: common module that imports angular material icon
and fontawesome
import { MatIconModule } from '@angular/material/icon';
...
// FontAwesome
import {
FontAwesomeModule,
FaIconLibrary,
} from '@fortawesome/angular-fontawesome';
import {
faBars,
faDonate,
…
} from '@fortawesome/free-solid-svg-icons';
…
export class ComunModule {
constructor(library: FaIconLibrary) {
library.addIcons(
faBars,
faDonate,
...
problemas.model.ts
export interface Problema {
id: number;
grupo: string;
idgrupo: number;
subgrupo?: string;
titulo: string;
encabezado?: string;
frase: string;
icon?: string;
ley: string;
parrafounotitulo?: string;
parrafounoparrafo?: string;
parrafounoimg?: string;
parrafodostitulo?: string;
parrafodosparrafo?: string;
parrafodosimg?: string;
parrafotrestitulo?: string;
parrafotresparrafo?: string;
parrafotresimg?: string;
parrafotablaa1?: string;
parrafotablaa2?: string;
parrafotablab1?: string;
parrafotablab2?: string;
parrafotablac1?: string;
parrafotablac2?: string;
parrafotablad1?: string;
parrafotablad2?: string;
}
problema.component.html
<div class="mostrando">
<mat-chip-list aria-label="Icono">
<mat-chip>
<h4>{{ "problemas.problemas.icon" | transloco }}:</h4>
<mat-icon><fa-icon icon="{{ problema.icon }}"></fa-icon></mat-icon>
</mat-chip>
</mat-chip-list>
</div>
</div>
...
problema.component.ts
import {
Component,
OnInit,
ChangeDetectionStrategy,
OnDestroy,
} from '@angular/core';
import { ActivatedRoute } from '@angular/router';
// import { untilDestroyed } from 'ngx-take-until-destroy';
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
import { filter, map, switchMap } from 'rxjs/operators';
import { ANIMACIONES_RUTA_ELEMENTOS } from 'src/app/nucleo/nucleo.module';
import { ProblemasQuery } from 'src/app/pages/problemas/state/problemas.query';
import { ProblemasService } from 'src/app/pages/problemas/state/problemas.service';
@UntilDestroy()
@Component({
selector: 'bab-problema',
templateUrl: './problema.component.html',
styleUrls: ['./problema.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ProblemaComponent implements OnInit, OnDestroy {
rutaAnimacionesElementos = ANIMACIONES_RUTA_ELEMENTOS;
problema$ = this.problemasQuery.selectEntity(this.problemaId);
constructor(
private activatedRoute: ActivatedRoute,
private problemasQuery: ProblemasQuery,
private problemasService: ProblemasService
) {}
ngOnInit(): void {
this.activatedRoute.paramMap.pipe(
map((params) => params.get('id')),
filter((id) => !this.problemasQuery.hasEntity(id)),
untilDestroyed(this),
switchMap((id) => this.problemasService.getProblemaPorId(id))
);
}
get problemaId(): any {
return this.activatedRoute.snapshot.params.id;
}
ngOnDestroy(): void {}
}
problemas.service.ts
@Injectable({ providedIn: 'root' })
export class ProblemasService {
filtrosProblemas: AkitaFiltersPlugin<ProblemasState>;
constructor(
private problemasStore: ProblemasStore,
private problemasQuery: ProblemasQuery
) {
this.filtrosProblemas = new AkitaFiltersPlugin<ProblemasState>(
this.problemasQuery
);
}
get(): Observable<Problema[]> {
return timer(500).pipe(mapTo(problemas));
}
getProblemas(): Observable<Problema[]> {
const request$ = this.get().pipe(
tap((resp) => {
this.problemasStore.set(resp);
})
);
const requestUpdate$ = this.get().pipe(
tap((resp) => {
this.problemasStore.remove();
this.problemasStore.set(resp);
})
);
return this.problemasQuery.getHasCache() === false
? request$
: requestUpdate$;
// return request$;
}
getProblemaPorId(id: any): Observable<any> {
const problema = problemas.find((current) => current.id === id);
return timer(500).pipe(
mapTo(problema),
map(() => this.problemasStore.add(problema))
);
}
package.json
"dependencies": {
"@agm/core": "^3.0.0-beta.0",
"@angular/animations": "~11.0.6",
"@angular/cdk": "^11.0.3",
"@angular/common": "~11.0.6",
"@angular/compiler": "~11.0.6",
"@angular/core": "~11.0.6",
"@angular/forms": "~11.0.6",
"@angular/material": "^11.0.3",
"@angular/platform-browser": "~11.0.6",
"@angular/platform-browser-dynamic": "~11.0.6",
"@angular/router": "~11.0.6",
"@datorama/akita": "^4.22.0",
"@fortawesome/angular-fontawesome": "^0.8.1",
"@fortawesome/fontawesome-common-types": "^0.2.34",
"@fortawesome/fontawesome-free": "^5.15.1",
"@fortawesome/fontawesome-svg-core": "^1.2.34",
"@fortawesome/free-brands-svg-icons": "^5.15.1",
"@fortawesome/free-solid-svg-icons": "^5.15.1",
"@ngneat/transloco": "^2.20.0",
"@ngneat/transloco-locale": "^1.4.0",
"@ngneat/until-destroy": "^8.0.3",
"akita-filters-plugin": "^4.0.0",
"bootstrap": "^4.5.3",
"browser-detect": "^0.2.28",
"moment": "^2.29.1",
"ngx-take-until-destroy": "^5.4.0",
"rxjs": "~6.6.0",
"tslib": "^2.0.0",
"zone.js": "~0.10.2"
},
...
package-lock.json
"@fortawesome/angular-fontawesome": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/@fortawesome/angular-fontawesome/-/angular-fontawesome-0.8.1.tgz",
"integrity": "sha512-dNmtFb/LTYWLNRfkKgCFwxgtQslNZLwUC+u7lkVAcIcjirIG6J9Ff0evl+9zR4DXFAkP0PN4RKe14NVDP3rUWA==",
"requires": {
"tslib": "^2.0.3"
}
},
"@fortawesome/fontawesome-common-types": {
"version": "0.2.34",
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.34.tgz",
"integrity": "sha512-XcIn3iYbTEzGIxD0/dY5+4f019jIcEIWBiHc3KrmK/ROahwxmZ/s+tdj97p/5K0klz4zZUiMfUlYP0ajhSJjmA=="
},
"@fortawesome/fontawesome-free": {
"version": "5.15.2",
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-5.15.2.tgz",
"integrity": "sha512-7l/AX41m609L/EXI9EKH3Vs3v0iA8tKlIOGtw+kgcoanI7p+e4I4GYLqW3UXWiTnjSFymKSmTTPKYrivzbxxqA=="
},
"@fortawesome/fontawesome-svg-core": {
"version": "1.2.34",
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-1.2.34.tgz",
"integrity": "sha512-0KNN0nc5eIzaJxlv43QcDmTkDY1CqeN6J7OCGSs+fwGPdtv0yOQqRjieopBCmw+yd7uD3N2HeNL3Zm5isDleLg==",
"requires": {
"@fortawesome/fontawesome-common-types": "^0.2.34"
},
"dependencies": {
"@fortawesome/fontawesome-common-types": {
"version": "0.2.34",
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.34.tgz",
"integrity": "sha512-XcIn3iYbTEzGIxD0/dY5+4f019jIcEIWBiHc3KrmK/ROahwxmZ/s+tdj97p/5K0klz4zZUiMfUlYP0ajhSJjmA=="
}
}
},
"@fortawesome/free-brands-svg-icons": {
"version": "5.15.2",
"resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-5.15.2.tgz",
"integrity": "sha512-YPlVjE1cEO+OJ9I9ay3TQ3I88+XkxMTYwnnddqAboxLhPNGncsHV0DjWOVLCyuAY66yPfyndWwVn4v7vuqsO1g==",
"requires": {
"@fortawesome/fontawesome-common-types": "^0.2.34"
}
},
"@fortawesome/free-solid-svg-icons": {
"version": "5.15.2",
"resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.15.2.tgz",
"integrity": "sha512-ZfCU+QjaFsdNZmOGmfqEWhzI3JOe37x5dF4kz9GeXvKn/sTxhqMtZ7mh3lBf76SvcYY5/GKFuyG7p1r4iWMQqw==",
"requires": {
"@fortawesome/fontawesome-common-types": "^0.2.34"
}
},
...
When compiling the app the icon looks and works, but it throws the error TS2322 Type ‘string’ is not assignable to Type ‘IconProp’:
However, the icon is perfectly visible when the app manages to launch with "ng serve":
What I have tried without it working:
- Switch to
"strict" = false;
in compilerOptions in tsconfig.json. - Read the instructions for angular-fontawesome in its official documentation.
- Import * IconProp *, and others like * IconName *, from
@fortawesome / fontawesome-svg-core
and assign it to the optional property"icon ?: string;"
:“icon?: IconProp;”
“icon?: IconProp | string;”
“icon?: IconProp | IconName | string;”
- Install
”@ fortawesome / fontawesome-common-types":"^ 0.2.34"
and set all libraries@fortawesome/*
with the same version offontawesome-common-types
, as advised by this issue - Delete
node_modules
andpackage-lock.json
, then runnpm i @ fortawesome / fontawesome-svg-core --save
andnpm install
following this issue
I thank you in advance for all the invaluable help that you can give me. Thank you.
UPDATE: the solution to the problem.
I found the problem in setting angularCompilerOptions
in tsconfig.json
with the option of "strictTemplates ": true
which enables strict mode
.
According to the official angular documentation when strictTemplates
is true what we do is enable the strict checking of the template type, which is only available with Ivy since angular version 9 and later.
The strict mode already failed me when I used the agm library for the web app maps, so I have disabled strictTemplates
. So I disabled strict templates and the compile error no longer appears. This seems to be the only solution, since I have no alternative to the parameter "icon?: string;", which is of type IconProp, and at the same time combining it with the angular interpolation in the html template.
the best way to bind string as font awesome icon
1- you must add this package @fortawesome/fontawesome-common-types
2- in your .ts file add this
3- in your HTML file add this
notice: use font awesome for angular from here