Passing variable into [icon] for Font Awesome not working - html

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

Related

Lazy loading route remains unchanged even after passing id

Library is the parent component. In Home page, when I click on Library icon, I am led to Library page with URL localhost:4200/library, which is expected. In Library page, there's list of books. When I click on a book, I am led to book details of the selected book. However, the URL still remains localhost:4200/library which I would like to change to localhost:4200/library/book/selected-book-id.
Here's my attempt at it. The problem is the URL still remains localhost:4200/library, I would really appreciate some guidance.
library.routing.module.ts
const routes: Routes = [
{
path: '',
pathMatch: 'full',
component: LibraryComponent
},
{
path: '**',
redirectTo: ''
},
{
path: 'library/book/:selectedBookId',
component: BookComponent
}
];
#NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class LibraryRoutingModule {}
library-list.component.html
<div content class="content">
<scroll-viewer
class="library-list"
>
<mat-list data-custom-parent-group="LibraryList" data-custom-parentid="library-list">
<div class="loading" *ngIf="!ready">
<waiting-spinner
[size]="waitingSpinnerSize.Medium"
></waiting-spinner>
</div>
<ng-container *ngIf="ready">
<mat-list-item role="listitem" *ngFor="let book of library" style="margin-bottom: 2rem;height: auto;">
<button
mat-raised-button
class="menu-button"
[routerLink]="['/', 'library', '/', 'book', '/', book.id]"
routerLinkActive="active"
[ngClass]="{
unknown: true,
valid: false,
warning: false,
issue: false
}"
(click)="selectBook(book)"
[attr.data-custom-name]="book.id"
[attr.data-custom-name]="book.name"
[attr.data-custom-bhvr]="'Book'">
<div style="display: flex;place-content: space-between;align-items: center;line-height: 7rem;">
<div style="display: flex;">
<div class="book-subitem">
<div class="book-element">
<div class="book-name">Book: </div>
</div>
</div>
</div>
</div>
</button>
</mat-list-item>
<router-outlet></router-outlet>>
</ng-container>
</mat-list>
</scroll-viewer>
<mat-paginator #paginator class="paginator" [length]="resultsLength" [pageSize]="pageLength" [pageSizeOptions]="[5, 10, 25, 50, 100]" (page)="updatePage($event)"></mat-paginator>
</div>
</daui-layout-filter>

Angular NgFor Path Issue

In my Angular Application I have a simple ngFor loop showing logo images like this:
<div *ngFor="let item of list" class="logo-wrapper">
<div class="customer-logo">
<span
class="my-icon"
aria-label="My icon"
[inlineSVG]="'./assets/image/projects/logo/' + item.logo">
</span>
</div>
</div>
This is working fine!
But: If I try to slice the Array to limit the output as follow:
<div *ngFor="let item of list | slice: 0:10; let i = index" class="logo-wrapper">
<div class="customer-logo">
<span
class="my-icon"
aria-label="My icon"
[inlineSVG]="'./assets/image/projects/logo/' + item.logo">
</span>
</div>
</div>
I get this Error : "Object is of type 'unknown'".
Error output:
I really don't know what I'm doing wrong here. I hope someone can point me in the right direction.
Edit: The problem appears as soon as I add a index to the loop.
I tried to add the index to the object like: item.i.logo but its also unknown.
PS: Here is my .ts-file
#Component({
selector: 'app-logo-section',
templateUrl: './logo-section.component.html',
styleUrls: ['./logo-section.component.scss']
})
export class LogoSectionComponent implements OnInit {
list : any
constructor()
{
this.list = getProjects()
console.log(this.list)
}
ngOnInit(): void
{
}
private services = [{
slug : "s-l-u-g",
name : "name",
work : "work",
company : "company",
website : "https://www.google.com",
preview : "text",
logo : "logo.svg"
}]
getProjects()
{
return services
}
}
You would have to change the type of list to any[] instead of any. Update the declaration as follows in your typescript file.
list : any[];
It seems like the SlicePipe deprecates with the ng-inline-svg package because it uses HttpClientModule and works asynchronously.
if you use Array.slice method instead of the SlicePipe in the *ngFor it works fine.
Please find the Stackblitz example.
<div *ngFor="let item of list.slice(0, 10); let i = index" class="logo-wrapper">
<div class="customer-logo">
<span class="my-icon" aria-label="My icon" [inlineSVG]="item.logo"> </span>
</div>
</div>

Access nested json object angular 6

I'm trying to access the nested data from the HTML template, but I get undefined or I get nothing as result (empty page with no class list or student list).
The HTML template:
<div class="container">
<label *ngFor="let class of listClass | keyvalue">
<span> {{class.value.name}} </span>
</label>
<div>
<label *ngFor="let student of class.students | keyvalue">
<span>{{student.value.fullName}} </span>
</label>
</div>
</div>
This is the fonction that gets the list of class and the students in it:
getListClasseStudent(){
this.classService.getStudents().subscribe((data) => {
this.listClass = data;
});
}
The nested data:
class:
0:{
code: "Math01"
teacher:
0: {id: 17551, name "Jack"}
students:
0: {studentId: 1, fullName: "Patrick bob"}
1: {studentId: 2, fullName: "Alice Alice"}
}
1:{
code: "English01"
teacher:
0: {id: 2, name "Nicolas"}
students:
0: {studentId: 1, fullName: "Patrick bob"}
1: {studentId: 2, fullName: "Alice Alice"}
}
I want to access to the list of student of each class, is there any efficient way to do it? thanks in advance.
<div class="container">
<div *ngFor="let c of listClass ">
<label >
<span> {{c.code}} </span>
</label>
<div>
<label *ngFor="let student of c.students ">
<span>{{student.fullName}} </span>
</label>
</div>
</div>
Try this (example without your pipe)
A 'Class' object don't have a attribute 'value.name' (probably gonna be injected by your pipe '| keyvalue' ).
Second *ngFor need t be inside of first, because he need's to iterate a students array, inside each class.
I hope this helps.
create a pipe like below
import { Pipe, PipeTransform } from "#angular/core";
#Pipe({ name: 'ObjNgFor', pure: false })
export class ObjNgFor implements PipeTransform {
transform(value: Object): Array<string> { return Object.keys(value); }
}
import the above pipe in app.module.ts and use pipe in the html page like below
<div *ngFor="let key of questions | ObjNgFor" class="row">
{{ questions[key].name}}
<div *ngFor="let r of questions[key].sub_sections | ObjNgFor ; let indx=index"
class="card-body">
{{ questions[key].sub_sections[r].name }}"
</div>
This example should work

Add Active class for multiple routes in Angular

I have a side bar which has multiple option in it.I set routerLinkActive class to make particular option active when click but now if I go deeper or other route from that route,the active class is being removed.I wanted to stay one option active for multiple routes.
My HTML code is as per below.
<div class="nav-list">
<ul class="listing" >
<li routerLinkActive="active" [routerLinkActiveOptions]="{exact: true }" >
<a [routerLink]="['/']" (click)="disableOptions()" >
<i class="fas fa-archive"></i> Projects
</a>
</li>
<li routerLinkActive="active" [routerLinkActiveOptions]="{ exact: true }" [class.disabled]="isDisabled==true">
<a [routerLink]="['/notebooks']" [style.pointer-events]="isDisabled ? 'none' : 'auto'" >
<i class="fas fa-book"></i> Notebooks
</a>
</li>
<li routerLinkActive="active" [routerLinkActiveOptions]="{ exact: true }" [class.disabled]="isDisabled==true" >
<a [routerLink]="['/files']" [style.pointer-events]="isDisabled ? 'none' : 'auto'">
<i class="fas fa-file-alt"></i> Files
</a>
</li>
<li routerLinkActive="active" [routerLinkActiveOptions]="{ exact: true }" [class.disabled]="isDisabled==true">
<a [routerLink]="['/screens']" [style.pointer-events]="isDisabled ? 'none' : 'auto'">
<i class="fas fa-desktop"></i>Screen
</a>
</li>
<li routerLinkActive="active" [routerLinkActiveOptions]="{ exact: true }" [class.disabled]="isDisabled==true">
<a [routerLink]="['/slides']" [style.pointer-events]="isDisabled ? 'none' : 'auto'">
<i class="fas fa-photo-video"></i> Slides
</a>
</li>
</ul>
</div>
As you can see in first image the route is ['/'] so the active class working fine but in second image the route is ['project/create'] so that the active class is not showing.I want to keep active class for both routes .Please help me to solve this issue.Thank you
My route file is like this.
const routes: Routes = [{
path: '',
component: PagesComponent,
canActivate: [AuthGaurdService],
children: [{
path: '',
component: ProjectListingComponent,
}, {
path: 'slides',
component: ScreenListingComponent,
}, {
path: 'project',
loadChildren: './multi-step-form/multistepform.module#MultistepformModule',
}, {
path: 'project/slide/create',
component: AddEditScenarioComponent
},
{
path: 'project/slide/edit',
component: DragDropToolScenarioComponent
},
{
path: 'notebooks',
component: NotebookListingComponent
},
{
path: 'screens',
component: ScreenTableComponent
},
{
path: 'files',
component: FileListingComponent
},
{
path: 'screens/create',
component: ScreenCreateComponent
},
{
path: 'files/create',
component: FileCreateComponent
},
{
path: 'notebook/create',
component: NotebookCreateComponent
}
]
}];
['project/create'] is in multistepform component which has its own routing file.
You can use nested routing for it. For example define your routes as
routes: Route[] = [
{ path: '', component: PagesComponent, children: [
{ path: 'project', component: ProjectComponent, children: [
{ path: 'slide/create', component: CreateProjectComponent }
]}
]}
];
And then you can have a <router-outlet> inside the PagesComponent and the ProjectComponent. The routerLinkActive will then react to the project/** route in the PagesComponent so it does not matter what follows. The routerLinkActive in the ProjectComponent will then be active for project/slide/create or whatever you route to. And I think you do not need the routerLinkActiveOptions.

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>