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>
Related
I am using Font Awesome with Angular.
I want to loop through some data via *ngFor to create icons in a navigation bar. However, the [icon] is not accepting the values from the variable.
Component HTML
<div class="navbar-container container" [ngClass] = "expanded ? 'navbar-collapsed': ''">
<div class="navbar-logo-container">
<button class="logo" (click)="toggleCollapsed()">
A
</button>
<div class="logo-text" *ngIf="expanded">My Site</div>
</div>
<ul class="navbar-nav">
<li class="navbar-nav-item" *ngFor="let data of navData">
<a class="navbar-nav-link" [routerLink]="[data.routeLink]">
//works
<fa-icon [icon]="['fas','star']"></fa-icon>
//Error: Type 'string' is not assignable to type 'IconProp'.
<fa-icon [icon]="data.iconfull"></fa-icon>
// Type 'string' is not assignable to type 'IconProp'.
<fa-icon [icon]="[data.iconfirst,data.iconsecond]"></fa-icon>
<span class="navbar-link-text" *ngIf="expanded">{{data.label}}</span>
</a>
</li>
</ul>
</div>
Data
export const navbarData = [
{
routeLink: 'dashboard',
iconfirst: 'fas',
iconsecond: 'star',
iconfull: "['fas','star']",
label: 'Dashboard'
}
]
Cannot reproduce the third scenario.
From IconProp,
export type IconProp = IconName | [IconPrefix, IconName] | IconLookup;
Hence, for the second scenario,
Specify the navbarData type as:
import {
IconProp,
IconPrefix,
IconName,
} from '#fortawesome/fontawesome-svg-core';
navbarData: {
routeLink: string;
iconfirst: IconPrefix;
iconsecond: IconName;
iconfull: IconProp;
label: string;
}[] = [
{
routeLink: 'dashboard',
iconfirst: 'fas',
iconsecond: 'star',
iconfull: ['fas', 'star'],
label: 'Dashboard',
},
];
Sample Demo on StackBlitz
I am struggling with this for a while now. I am trying to upload an image using ng-upload in angular, the file is saved in the database, however I am receiving 'Cannot read properties of undefined' when the upload queue is over. Code used for receiving the file:
Upload.html
<div class="container text-center" *ngIf="memeUploadMode">
<div class="row mt-3">
<div class="col-md-3">
<h3>Dodaj mema</h3>
<div ng2FileDrop
[ngClass]="{'nv-file-over': hasBaseDropzoneOver}"
(fileOver)="fileOverBase($event)"
[uploader]="uploader"
class="card bg-faded p-3 text-center mb-3 my-drop-zone">
<i class="fa fa-upload fa-3x"></i>
Przeciągnij mema tutaj
</div>
<input type="file" ng2FileSelect [uploader]="uploader" />
</div>
<div class="col-md-9" style="margin-bottom: 40px" *ngIf="uploader?.queue?.length">
<h3>Kolejka</h3>
<p>Długość kolejki: {{ uploader?.queue?.length }}</p>
<table class="table">
<thead>
<tr>
<th width="50%">Nazwa</th>
<th>Rozmiar</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let item of uploader.queue">
<td><strong>{{ item?.file?.name }}</strong></td>
<td *ngIf="uploader.options.isHTML5" nowrap>{{ item?.file?.size/1024/1024 | number:'.2' }} MB</td>
</tr>
</tbody>
</table>
<div>
<div>
Queue progress:
<div class="progress">
<div class="progress-bar" role="progressbar" [ngStyle]="{ 'width': uploader.progress + '%' }"></div>
</div>
</div>
<button type="button" class="btn btn-success btn-s"
(click)="uploader.uploadAll()" [disabled]="!uploader.getNotUploadedItems().length">
<span class="fa fa-upload"></span> Upload all
</button>
</div>
</div>
</div>
And here's the code where I'm trying to add the image to the member object:
Upload.ts
constructor(public accountService: AccountService, private memberService: MembersService,
private router: Router, private toastr: ToastrService) {
this.accountService.currentUser$.pipe(take(1)).subscribe(user => this.user = user);
}
ngOnInit(): void {
this.initializeUploader();
}
fileOverBase(e: any) {
this.hasBaseDropzoneOver = e;
}
deletePhoto(photoId: number) {
this.memberService.deletePhoto(photoId).subscribe(() => {
this.member.photos = this.member.photos.filter(x => x.id !== photoId);
})
}
initializeUploader() {
this.uploader = new FileUploader({
url: this.baseUrl + 'users/add-meme',
authToken: 'Bearer ' + this.user.token,
isHTML5: true,
allowedFileType: ['image'],
removeAfterUpload: true,
autoUpload: false,
maxFileSize: 10 * 1024 * 1024
});
this.uploader.onAfterAddingFile = (file) => {
file.withCredentials = false;
}
this.uploader.onSuccessItem = (item, response, status, headers) => {
if (response) {
const meme: Meme = JSON.parse(response);
this.member.memes.push(meme);
this.user.memeUrl = meme.url;
this.member.memeUrl = meme.url;
this.accountService.setCurrentUser(this.user);
}
}
}
memeToggle() {
this.memeUploadMode = !this.memeUploadMode;
}
The error occurs at this line:
this.member.memes.push(meme);
I've already looked at similar questions, however none of the answers helped me. I must add that I already have a similar feature for adding user's photos, which is set up identically and it works. Any help would be much appreaciated.
Cheers,
Filip
You should define member in your component
member = {
memes: [],
memeUrl: ''
};
Ah, right. I see. I had those in my Upload.ts file when the error occured:
#Input() member: Member;
members: Member[];
memes: Meme[] = [];
model: any = {}
uploader: FileUploader;
After defining the member as you suggested, the compiler asked me to define every other attribute as well. Now it works, you are my savior, my good Sir :)
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
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>
I want to display in a card in angular project for example the count number of row . To get the data from mysql i'm using a service.
here is the service data :
private _postsURL = "http://localhost:3003/all";
constructor(private http: Http) {
}
getcount(): Observable<ICustomer[]> {
return this.http
.get(this._postsURL)
.map((response: Response) => {
return <ICustomer[]>response.json();
})
.catch(this.handleError);
}
component.ts
getcount(): void {
this.apiSerivce.getcount()
.subscribe(
resultArray => this._count = [resultArray[0]],
error => console.log("Error :: " + error)
)
}
ngOnInit(): void {
this.getcount();
component.html
<div class="card">
<div class="card-body">
<div class="row">
<div class="col-12" *ngFor="let post of _count">
<h2 class="m-b-0"><i class="mdi mdi-buffer text-
warning"></i></h2>
<h3 class="">{{post}}</h3>
<h6 class="card-subtitle">Total Earnings</h6>
</div>
<div class="col-12">
<ngb-progressbar [showValue]="false"
type="warning" [value]="50"></ngb-progressbar>
I want to populate the card only with the value fetch from api.
API response is an asynchronous event and ngOnInit method execution completes before it gets response from backend call so, you should render the card section view only if _count variable binding got value in it and you can achieve it by adding ngIf directive on root-card html element as below.
<div class="card" *ngIf="_count?.length > 0">
<div class="card-body">
<div class="row">
<div class="col-12" *ngFor="let post of _count">
<h2 class="m-b-0"><i class="mdi mdi-buffer text-
warning"></i></h2>
<h3 class="">{{post}}</h3>
<h6 class="card-subtitle">Total Earnings</h6>
</div>
<div class="col-12">
<ngb-progressbar [showValue]="false"
type="warning" [value]="50"></ngb-progressbar>