Transform Word into Icon in Angular - html

I'm have a page that the footer contains a lot of info of a gym, Contact, Location etc...
The gym i picked for example contains 5 means of contact, that are:
Commercial Phone
Whatsapp
Instagram
Facebook
Email
This is how the json look like:
"ExibirContatos": [
{
"ID_TipoContato": "2",
"TipoDescricao": "Telefone comercial",
"Contato": "(31)2523-0672"
},
{
"ID_TipoContato": "9",
"TipoDescricao": "Whatsapp",
"Contato": "(31)98428-6287"
},
{
"ID_TipoContato": "5",
"TipoDescricao": "Instagram",
"Contato": "#br_fit_"
},
{
"ID_TipoContato": "7",
"TipoDescricao": "Facebook",
"Contato": "https://www.facebook.com/brfitbh/"
},
{
"ID_TipoContato": "4",
"TipoDescricao": "E-mail",
"Contato": "contato#brfitbh.com.br"
}
]
TS:
import {HttpClient} from '#angular/common/http';
import { Academia } from '../../classes/academia';
interface AcademiaRequest {
ACADEMIA_INFO: any;
}
export class HomePageComponent implements OnInit {
academia: Academia = new Academia();
constructor(private http: HttpClient) {}
ngOnInit() {
this.receberAcademia(this.academia);
}
receberAcademia(academia) {
this.http
.get<AcademiaRequest>(
'http://fitgroup.com.br/vysor_vendas_online/fg_vendas.php?AuthToken=FlnPoU230xGF&Metodo=academiaLoad&IDCliente=000949'
)
.subscribe(response => {
academia.nome = response.ACADEMIA_INFO.AcademiaDados.NomeAcademia;
academia.rua = response.ACADEMIA_INFO.AcademiaDados.EnderecoLogradouro;
academia.numero = response.ACADEMIA_INFO.AcademiaDados.EnderecoNumero;
academia.cep = response.ACADEMIA_INFO.AcademiaDados.EnderecoCEP;
academia.cidade = response.ACADEMIA_INFO.AcademiaDados.EnderecoCidade;
academia.estado = response.ACADEMIA_INFO.AcademiaDados.EnderecoUF;
academia.contatos = response.ACADEMIA_INFO.VendasOnline.ExibirContatos;
});
}
}
Academia Class:
export class Academia {
registros: number;
nome: string;
// Endereço
rua: string;
numero: string;
cep: string;
cidade: string;
estado: string;
// Contato
contatos: any[];
}
And for last, my HTML:
<div class="col-lg-3 col-md-6 col-sm-6 mt-2 mb-4">
<h5 class="mb-4 ml-4 font-weight-bold">
CONTATO:
</h5>
<ul class="f-address">
<li *ngFor="let contatos of academia.contatos">
<p> {{contatos.TipoDescricao }}: {{ contatos.Contato }} </p>
</li>
</ul>
</div>
It's printing something like that:
But i don't want the name of the contact, i don't want "Telefone Comercial:", "Whatsapp" and etc... I want these names to be replaced by icons, fontawesome icons, these icons respectively:
<i class="fas fa-phone-alt"></i>
<i class="fas fa-whatsapp"></i>
<i class="fas fa-instagram"></i>
<i class="fas fa-facebook"></i>
<i class="fas fa-envelope"></i>
But i don't have any ideas how to do such a conversion, i even have thinked in this code:
<div class="col-lg-3 col-md-6 col-sm-6 mt-2 mb-4">
<h5 class="mb-4 ml-4 font-weight-bold">
CONTATO:
</h5>
<ul class="f-address">
<li *ngFor="let contatos of academia.contatos">
<p> <i class="fas {{ contatos.TipoDescricao }}"></i> {{ contatos.Contato }} </p>
</li>
</ul>
</div>
But first i need to convert to the rest of the icon's name "fa-icon_name", how can i do that? Please help me!!

I can see two ways to solve this:
1 - Create a method to get the icon correspondent to the description, but it would impact the performance as it would be called on every change.
2 - Create a pipe, which is the recommended way:
import { Pipe, PipeTransform } from '#angular/core';
// Note that I have used Font Awesome 5.x for this demo.
const descriptionIconClassMapper = {
'E-mail': 'fas fa-envelope',
'Telefone comercial': 'fas fa-phone-alt',
Facebook: 'fab fa-facebook',
Instagram: 'fab fa-instagram',
Whatsapp: 'fab fa-whatsapp'
};
#Pipe({
name: 'descriptionToIconClass'
})
export class DescriptionToIconClassPipe implements PipeTransform {
transform<T extends keyof typeof descriptionIconClassMapper>(
description: T
): typeof descriptionIconClassMapper[T] {
return descriptionIconClassMapper[description];
}
}
And in HTML:
<div class="col-lg-3 col-md-6 col-sm-6 mt-2 mb-4">
<h5 class="mb-4 ml-4 font-weight-bold">
CONTATO:
</h5>
<ul class="f-address" *ngIf="academiaInfo$ | async as academiaInfo">
<li *ngFor="let contato of academiaInfo.VendasOnline.ExibirContatos">
<p><i class="mr-1" [ngClass]="contato.TipoDescricao | descriptionToIconClass"></i>{{ contato.Contato }}</p>
</li>
</ul>
</div>
Some tips:
1 - Do not call http requests directly from components. Create a service to wrap this;
2 - Instead of subscribe, prefer to use async pipe for GET requests;
3 - Instead of using any, you can use a tool to generate typescript interfaces from a JSON, like http://jsontots.com.
4 - Unless you have a good reason to use class, prefer interfaces, as it wouldn't affect build size.
5 - See the DEMO :)

You can use a pipe to achieve that. Create a pipe that takes your contatos.TipoDescricao as an input and returns the matching icon for that.
#Pipe({
name: 'descriptionToIcon'
})
export class DescriptionToIconPipe implements PipeTransform {
private static readonly iconsForDescriptions:Array<{desc:string, icon:string}> = [
{desc: 'Telefone comercial', icon: 'fa-phone-alt'},
// Add all other texts and icons as pairs as well
]
transform(value: any, args?: any): any {
return DescriptionToIconPipe.iconsForDescriptions.find(item => item.desc === value).icon;
}
}
And in your HTML
<div class="col-lg-3 col-md-6 col-sm-6 mt-2 mb-4">
<h5 class="mb-4 ml-4 font-weight-bold">
CONTATO:
</h5>
<ul class="f-address">
<li *ngFor="let contatos of academia.contatos">
<p> <i class="fas {{ contatos.TipoDescricao | descriptionToIcon}}"></i> {{ contatos.Contato }} </p>
</li>
</ul>
</div>

Related

How to pass value from one component to another? (Angular)

I just recently started learning Angular and I have a question. I want to implement a search method to search for a product on my site, I made search.pipe.ts, which works, but the input for input is in the header.component.ts component, and the products array is in the car-list.component.ts component.
car-list.component.html
<div *ngFor="let car of cars | paginate: { itemsPerPage: pageNumber, currentPage: currentPg} | **search:searchStr**" class="col-md-3">
<div class="product box">
<img src="{{'data:image/jpg;base64,' + car.image }}" alt="">
<h3>{{ car.name }}</h3>
<div class="price">{{ car.price | currency:'USD' }}</div>
<button class="btn btn-primary btn-sm">Add to cart</button> <!--(click)="addToCart(tempProduct)"-->
</div>
<br>
</div>
header.component.html
<form class="d-flex me-5">
<input type="text" class="form-control me-2" placeholder="Search cars...">
</form>
header.component.ts
export class HeaderComponent implements OnInit {
searchStr: string = '';
constructor() {
}
ngOnInit(): void {
}
}
search.pipe.ts
#Pipe({
name: 'search'
})
export class SearchPipe implements PipeTransform {
transform(cars: any[], value: any) {
return cars.filter(car => {
return car.name.includes(value);
})
}
}
I want the input values ​​from the header component to be passed to the car-list component so that I can find the product I need.
In this case you can use a shared service where you can pass data from your header component and load that data in your products component.
For further reference - Angular 4 pass data between 2 not related components
use #Input and #Output decorators to communicate between components

Angular filter posts using pipes

I'm trying to filter posts of a table in Angular using pipes, but I keep getting on the console this error: core.js:12689 Can't bind to 'ngForFilter' since it isn't a known property of 'a'.
I think the error is on filter: filterPost, but dont know how to fix it. Any clue?
My html code is the following.
<div class="form-group">
<label for="exampleFormControlInput1">Busca un reporte</label>
<input type="text" class="form-control" id="exampleFormControlInput1" name="filterPost" placeholder="Busca.." [(ngModel)]="filterPost">
</div>
<a *ngFor="let report of All_reports | paginate: { itemsPerPage: 10, currentPage: actualPage }; let i = index;
filter: filterPost" class="list-group-item list-group-item-action flex-column align-items-start" [routerLink]="['/reporte-admin']"
routerLinkActive="router-link-active" (click)="onSubmit(report._id)">
<div class="d-flex w-100 justify-content-between">
<h5 class="mb-1">Reporte #: {{report._id}}</h5>
<small>{{i+1}}</small>
</div>
<p class="mb-1">Comentario: {{report.comentario}}</p>
<small class="text-muted">Nombre: {{report.nombre}} {{report.apellido}}</small>
</a>
<br>
This is my filter.pipe.ts code:
#Pipe({
name: 'filter'
})
export class FilterPipe implements PipeTransform {
transform(value: any, arg: any): any {
const resultPosts = [];
for(const report of value){
if(report._id.indexOf(arg) > -1){
resultPosts.push(report);
};
};
return resultPosts;
}
}
Pipe operator "|" expects some value to the left of it.
In your case, you added the pipe operator at the end after let i=index;
I believe you should do something like this
*ngFor="let report of All_reports | paginate: { itemsPerPage: 10, currentPage: actualPage } | filter: filterPost; let i = index;"
and also dont forget to add in declarations in app module

Angular 8 ERROR TypeError: Cannot read property 'name' of undefined

I am playing around with angular and I get this error: ERROR TypeError: Cannot read property 'name' of undefined
My code is
recipe-list.component.ts
import { Component, OnInit } from '#angular/core';
import { Recipe } from '../recipe.model'
#Component({
selector: 'app-recipe-list',
templateUrl: './recipe-list.component.html',
styleUrls: ['./recipe-list.component.css']
})
export class RecipeListComponent implements OnInit {
recipes: Recipe[] = [
new Recipe('Test', 'Test Code', 'https://cdn.pixabay.com/photo/2016/06/15/19/09/food-1459693_960_720.jpg'),
new Recipe('Test 2', 'Test Code', 'https://cdn.pixabay.com/photo/2016/06/15/19/09/food-1459693_960_720.jpg')
];
constructor() { }
ngOnInit() {
}
}
recipe-list.component.html
<div class="row">
<div class="div col-xs-12">
<button class="btn btn-success">New Recipe</button>
</div>
</div>
<hr>
<div class="row">
<div class="col-xs-12">
<app-recipe-item
*ngFor="let recipeEl of recipes"
[recipe]="recipeEl"></app-recipe-item>
</div>
</div>
<app-recipe-item></app-recipe-item>
recipe-item.compoent.html
<a href="#" class="list-group-item clearfix">
<div class="pull-left">
<h4 class="list-group-item-heading">{{ recipe.name }}</h4>
<p class="list-group-item-text">{{ recipe.description }}</p>
</div>
<span class="pull-right">
<img [src]="recipe.imagePath" alt="{{ recipe.name }}" class="img-responsive" style="max-height:50px">
</span>
</a>
recipe-item.component.ts
import {Component, Input, OnInit} from '#angular/core';
import {Recipe} from '../../recipe.model';
#Component({
selector: 'app-recipe-item',
templateUrl: './recipe-item.component.html',
styleUrls: ['./recipe-item.component.css']
})
export class RecipeItemComponent implements OnInit {
#Input() recipe: Recipe;
constructor() {
console.log('Recipe is' + this.recipe);
}
ngOnInit() {
}
}
I can't seem to find the problem with my code. Why is it adding a empty element shown in the screenshot
You can simply solve this by using the "safe navigation operator".
When you use the interpolation, it is recommended to use ? ("safe navigation") when the object may be undefined.
<a href="#" class="list-group-item clearfix">
<div class="pull-left">
<h4 class="list-group-item-heading">{{ recipe?.name }}</h4>
<p class="list-group-item-text">{{ recipe?.description }}</p>
</div>
<span class="pull-right">
<img [src]="recipe.imagePath" [alt]="recipe.name" class="img-responsive" style="max-height:50px">
</span>
</a>
This will clear your console problems, but you may need to *ngFor in a div that surrounds the component:
<div *ngFor="let recipeEl of recipes">
<app-recipe-item [recipe]="recipeEl"></app-recipe-item>
</div>
And a plus: when you are working inside a HTML tag, don't use interpolation, use property binding instead. (example [alt]="recipe.name")
I think I cracked this case: in your recipe-list component template you have <app-recipe-item></app-recipe-item> added at the end for some reason, seems like some leftover code.
The errors are likely being thrown by that component because there is no any input value provided to it. This also explains the empty element you have at the bottom of the screenshot.
Remove that and that should solve the console error you mentioned, and get rid of the empty element. Good luck!

Angular 6 *ngFor not updating view

I am using material card to get populated using *ngFor but it does not show binding
it shows this in the DOM ,but when I console my binded variable, it shows the value but still my mat-card not get re populated.
NOTE :-- when I click on any form field box its then changed to <!--bindings={
"ng-reflect-ng-for-of": "[object Object],[object Object"
}--> this and data starts showing
Below is my code
<mat-card class="inner-list-card" *ngFor="let uglist of userGroupViewModel.UserGroupList"
(click)="getDetails(uglist['groupId'],$event)" routerLink="scope">
<div class="inner-card">
<li class="pointer">
<span class="listIcon">
<i class="fa fa-users"></i>
</span>
<a class="textwrap">
{{ uglist.groupName }}
<small class="listDate">Last Updated: {{ uglist.updatedOn*1000 | date }}</small>
</a>
<span>
<a class="protected">
<img alt="" src="assets/protected.png" height="25px" width="23px">
</a>
</span>
</li>
</div>
<div class="desc"> {{ uglist.description }}</div>
<div class="routing-element">Show
More
<i class="fa fa-angle-right alignRight" aria-hidden="true"></i>
</div>
</mat-card>
and I went through the below reference links:
angular2 ngFor not working while fetching data from api on ngOnInit()
Welcome to asynchronous programming :)
You have not included the details of how you're getting the data from your api... what i have done is used observable to which i subscribed. As soon as the data is available, the *ngFor renders the result for us.
relevant service.ts:
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
#Injectable({
providedIn: 'root',
})
export class MyService {
apiURL: string = 'https://ddxhruyrrj.execute-api.us-east-2.amazonaws.com/aiProd/projectslazy';
constructor(private http: HttpClient) { }
getData() {
return this.http.get(this.apiURL);
}
}
relevant component.ts:
export class CardFancyExample {
dataSet:any;
constructor(private serv: MyService) {
this.serv.getData().subscribe(
dataa => { console.log(dataa); this.dataSet = dataa; }
, errr => { console.log(errr); }
)
}
}
relevant html:
<div *ngIf="dataSet== ''">
No data loaded
</div>
<div *ngIf="dataSet != ''">
<mat-card class="example-card" *ngFor="let data of dataSet">
<mat-card-header>
<mat-card-title>{{data?.project}}</mat-card-title>
<mat-card-subtitle>{{data?.role}}</mat-card-subtitle>
</mat-card-header>
<img mat-card-image src="https://www.akberiqbal.com/JumboMob.jpg" alt="Akber Iqbal">
<mat-card-content>
<p>
{{data?.description}}
</p>
</mat-card-content>
<mat-card-actions>
<button mat-button>LIKE</button>
<button mat-button>SHARE</button>
</mat-card-actions>
</mat-card>
</div>
complete working stackblitz here

access array inside array in angular 4

I'm using angular to create a web project that uses google's custom search engine to populate the web pages with the first ten results returned. The data I get back from the API is in JSON format which I can assess and display using an interface. I'm able access the array "items", my problem is I don't know how to access the array inside the items array. Any help is welcome. Ps. i'm new to angular.
interface ISite{
kind: string;
title: string;
htmlTitle: string;
link: string;
displayLink: string;
srcImage: string;
snippet: string;
}
//Second interface to deal the api
interface ISearchResponse {
kind: string;
context: string;
items: ISite[];
cse_images: string;
company: string;
snippet: string;
}
//and my service
constructor(private _http: HttpClient) { }
getSites(): Observable<ISearchResponse> {
return this._http.get<ISearchResponse>(this._siteURL)
.do(data => console.log('All: ' + JSON.stringify(data)))
.catch(this.handleError);
}
private handleError(err: HttpErrorResponse) {
console.log('SearchEngineService: ' + err.message);
return Observable.throw(err.message);
}
}
//My html
<h2>Search Results</h2>
<div class="list-group" *ngFor='let site of sites.items'>
<a href="{{site.link}}" class="list-group-item list-group-item-action flex-column align-items-start active" >
<div class="d-flex w-100 justify-content-between">
<h4 class="mb-1">Title: {{site.title}}</h4>
</div>
<h5>URL: {{site.link}}</h5>
<p class="mb-1">Description: {{site.snippet}}</p>
</a>
</div>
sample of the data form google api, I want to access the image in
cse_image
"items": [
{
"kind": "customsearch#result",
"title": "Sports News,Scores,Schedules,Standings,Stats,Photos",
"pagemap": {
"cse_image": [
{
"src": image.jpg"
}
]
}
},
Try this:
<h2>Search Results</h2>
<div class="list-group" *ngFor='let site of sites.items'>
<a href="{{site.link}}" class="list-group-item list-group-item-action flex-column align-items-start active" >
<div class="d-flex w-100 justify-content-between">
<h4 class="mb-1">Title: {{site.title}}</h4>
</div>
<h5>URL: {{site.link}}</h5>
<p class="mb-1">Description: {{site.snippet}}</p>
<img src={{site.pagemap.cse_image[0].src}}>
</a>
</div>