Conditional print on html of angular - javascript

I am looping through a list of products and then checking if the product Id is already present in an array of products(objects) , then printing the quantity else if the product is not in the object then trying to print 0. Below is the code I have tried till now.
<ion-item class="added" *ngFor="let item of fetchProducts();let key=index;">
<ng-container *ngFor="let cartitem of cart" >
<span class="count" *ngIf="cartitem.p_id==item.p_id;">
{{cartitem.qty}}
</span>
</ng-container>
</ion-item>
How to print 0 if item is not in the cartitem in same span.

You can simply do this using ternary operator like below.
<ng-container *ngFor="let cartitem of cart" >
<span class="count">
{{cartitem.p_id==item.p_id ? cartitem.qty : 0 }}
</span>
</ng-container>

Can use *ngIf else condition inside your for loop -
<ion-item class="added" *ngFor="let item of fetchProducts();let key=index;">
<ng-container *ngFor="let cartitem of cart">
<span class="count" *ngIf="cartitem.p_id==item.p_id; then content else other_content">
</span>
<ng-template #content>{{cartitem.qty}}</ng-template>
<ng-template #other_content>0</ng-template>
</ng-container>
</ion-item>

Instead of using template logic I would move the logic to the class.
cart and products are obviously available in the class.
Therefore adjust the fetchProducts function in the class to return the products list as needed (with the quantity information) and use a single ngFor loop in the template.
Or add a new function getProductsWithQuantity...
In your class
public getProductsWithQuantity() {
return this.fetchProducts().map(product => {
...product,
quantity: this.getQuantity(product);
});
}
private getQuantity(product) {
const foundCartItem = this.cart.find(cartItem => product.id === cartItem.id);
if (foundCartItem) {
return foundCartItem.qty;
}
return 0;
}
In your template:
<ion-item class="added" *ngFor="let item of getProductsWithQuantity();let key=index;">
<span class="count">
{{item.qty}}
</span>
...

Related

Applying a class to a array item which is not in the original array using angular

I have an array which displays data as mat-select dropdown. The user can select any tags he wants. Also we have some free form text field inside the dropdown of tags from which the user can create his own custom text apart from tags array. See below:
display.component.html
<mat-form-field class="full-width">
<mat-label class="full-width">Select Tag</mat-label>
<mat-select formControlName="tagsControl" [(ngModel)]="project.tags" multiple>
<mat-select-trigger>
<mat-chip-list>
<mat-chip *ngFor="let tagging of firstFormGroup.value.tagsControl" [removable]="true"
(removed)="onTaggingRemoved(tagging)">
{{ tagging }}
<mat-icon matChipRemove>cancel</mat-icon>
</mat-chip>
</mat-chip-list>
</mat-select-trigger>
<mat-option *ngFor="let tagging of tagsList"
[value]="tagging">{{tagging}}</mat-option>
<mat-form-field style="margin-left: 17px; margin-top: 8px;">
<input matInput placeholder="Add New Tag" #input>
</mat-form-field>
<button mat-stroked-button color="primary" style="margin-left: 4px;" class="common-button"
(click)="addNewTags(input.value)">
Add</button>
</mat-select>
</mat-form-field>
display.component.ts
onTaggingRemoved(tagging: string){
const taggings = this.firstFormGroup.value.tagsControl as string[];
this.removeFirst(taggings, tagging);
this.firstFormGroup.controls['tagsControl'].patchValue(taggings);
}
removeFirst<T>(array: T[], toRemove: T): void {
const index = array.indexOf(toRemove);
if (index !== -1) {
array.splice(index, 1);
}
}
addNewTags(value: string) {
this.tagsList.push(value);
}
table.component.ts
tags: string[] = ["Prod", "Stg", "Dev", "QA"];
table.component.html
<ng-container matColumnDef="tags">
<mat-header-cell *matHeaderCellDef>
Tags </mat-header-cell>
<mat-cell *matCellDef="let element; let i = index;">
<span *ngIf="element.tags && element.tags.length < 35" matTooltipPosition="above"
matTooltip="{{element.tags}}">
<span *ngIf="element.tags == 'Prod'">
<span class="badge badge-pill bg-info font-color-tags">{{ element.tags.join(', ') }}</span>
</span>
<span *ngIf="element.tags == 'Stg'">
<span class="badge badge-pill bg-primary font-color-tags">{{ element.tags.join(', ')}}</span>
</span>
<span *ngIf="element.tags == 'Dev'">
<span class="badge badge-pill bg-secondary font-color-tags">{{ element.tags.join(', ')}}</span>
</span>
<span *ngIf="element.tags == 'QA'">
<span class="badge badge-pill bg-success font-color-tags">{{ element.tags.join(', ')}}</span>
</span>
</span>
<span *ngIf="element.tags.length == 0">
-
</span>
</mat-cell>
</ng-container>
My question is i am adding the badges the color codes to different array items based in its value. I mean if the tags array item value is "QA", i am adding different color, similarly for "Prod" different color. But i need to add some custom badge color to the custom tag which user created on his own other than tags array. I am planning to add a unique badge to all custom color badge then how to achieve this?
Please help me.
Not sur I got your question but if I did, you want to apply to any new tag in the four you have the correct badge.
In this way, your html code have to be dynamic with [ngClass] like :
<span [ngClass]="method_to_return_badge(element.tags)">{{ element.tags.join(', ')}}</span>
You then have to define the method_to_return_badge in your ts and with a switch on the four possibilities return the right badge.
This will let you write less code in your html and make it more readable.
Hope it helps you

How to sort primeNg table with nested columns structure?

I am using primeNg . I want to implement sorting of data. The problem is that I have a column data structure where some columns have a superColumn type and that means they are divided for a set of subColumns. It works well for presenting but I have a problem with sorting it. It is never sorted on basis of the subcolumn field value but on the basis of the parent column (supercolumn) field value. That means it is taking what is in the [pSortableColumn] attribute instead of what is in the [field] attribute of the sorting icon.
Is there any way I could resolve that? This is my code below (I removed styling):
<th
*ngFor="let col of columns; let i = index;"
pResizableColumn
pReorderableColumn
[pSortableColumn]="col.field"
[pSortableColumnDisabled]="col.showSort === false"
>
<ng-container *ngIf="col.type !== 'superColumn'">
<span>{{ col.header }}</span>
<p-sortIcon [field]="col.field"></p-sortIcon>
</ng-container>
<ng-container *ngIf="col.type === 'superColumn'">
<div>{{ col.header }}</div>
<ng-container *ngFor="let subColumn of col.subColumns">
<div>
{{ subColumn.header }}
<p-sortIcon [field]="subColumn.field"></p-sortIcon>
</div>
</ng-container>
</ng-container>
</th>

Hiding elements using ngFor loop

I have a list of items i am getting from backend.
I do not want to show two items in UI.
I do not want to display Conference and reception in UI.
HTML Code:
<ng-container *ngFor="let space of space_name">
<div *ngIf="space">
<a class="dropdown-item text-light" [routerLink]="['/spaces']"
routerLinkActive="current"
[queryParams]="{space_name:space}" data-toggle="collapse"
data-target=".navbar-collapse.show"
style="background-color: #8d0528;">{{ space | uppercase }}</a>
</div>
</ng-container>
TS Code:
this.sharedService.getDropdownspace().subscribe(data => {
this.spaceDropdown = data;
this.api_data = Object.values(this.spaceDropdown);
this.space_name = this.api_data[0];
})
Please suggest me a approach to do this.
You can use the array filter method to do the same. Create a function in your component and use it on the *ngFor directive like below.
In your component create a function to filter the result.
filter(itemList: space_name[]): space_name[] {
let result: space_name[] = [];
result = itemList.filter(item => {
return (item != "Conference" && item != "Reception")
});
return result;
}
In your template file
<ng-container *ngFor="let space of filter(space_name)">
<div *ngIf="space">
<a class="dropdown-item text-light" [routerLink]="['/spaces']" routerLinkActive="current" [queryParams]="{space_name:space}" data-toggle="collapse" data-target=".navbar-collapse.show" style="background-color: #8d0528;">{{ space | uppercase }}</a>
</div>
</ng-container>
Code and Demo: https://jsfiddle.net/ybdmrL2z/

Change HTML in Angular 7 by reference

I'm passing UL by reference in an Angular function and I want to append some 'li' in that UL.
<ng-container *ngIf="FileUploaded">
<tr class="" *ngFor="let row of this.fileJson">
<td class="text-left">{{row.Comment}}</td>
<td class="text-center">
<div class="tags">
<ul class="tags tags--ds ui-sortable" #forAddingTag> // This is the reference which is passed in below button's function named "AddTag()"
<ng-container *ngFor="let key of this.Object.keys(row)">
<li #ToRemoveTag class="tags__item" *ngIf="key.substring(0,5)=='Topic'">
<p>{{row[key]}}</p> <span class="close__item"><i class="fal fa-times"
(click)="removeTag(ToRemoveTag)"></i></span>
</li>
</ng-container>
</ul>
</div>
</td>
<td class="text-center">
<a class="btn" (mousedown)="AddTag(forAddingTag)">Update</a> // Here the reference is being passed
</td>
</tr>
</ng-container>
Here is the typescript code
AddTag(evalue){
debugger
var text = "";
if (window.getSelection) {
text = window.getSelection().toString();
}
var value = text;
}
I just want to add some more "li" at the end of this UL. I can do it with the help of JQuery but it shouldn't be used in Angular.
I'd recommend not to run any function in the *ngFor tag. It'll be called too many times than you think it does. Better way would be to create another object in the controller (something like filteredRows) and loop over it in the template with the keyvalue pipe.
Template
<ng-container *ngIf="FileUploaded">
<tr class="" *ngFor="let row of filteredRows; let rowIndex=index">
<td class="text-left">{{ row.comment }}</td>
<td class="text-center">
<div class="tags">
<ul class="tags tags--ds ui-sortable" #forAddingTag>
<ng-container *ngFor="let topic of filteredRows.topics | keyvalue; let topicIndex=index">
<li #ToRemoveTag class="tags__item">
<p>{{ topic.value }}</p> <span class="close__item"><i class="fal fa-times"(click)="removeTag(rowIndex, topicIndex)"></i></span>
</li>
</ng-container>
</ul>
</div>
</td>
<td class="text-center">
<a class="btn" (mousedown)="addTag(rowIndex)">Update</a>
</td>
</tr>
</ng-container>
Then you could modify the filteredRows variable (add/remove properties) to reflect the changes in the template.
Controller
filteredRows: {comment: any, topics: any[]}[];
ngOnInit() {
fileJson.forEach(row => {
const comment = row['Comment'];
const topics = JSON.parse(JSON.stringify(row)); // <-- create a deep copy of `row` object
for (const key in topics) {
if (topics.hasOwnProperty(key)) {
if (key.substring(0, 5) !== 'Topic') {
delete topics[key];
}
}
}
this.filteredRows.push({comment: comment, topics: topics});
});
}
addTag(index) {
this.filteredRows[index].topics.push(
{
// object content
}
);
}
removeTag(rowIndex, topicIndex) {
delete this.filteredRows[rowIndex].topics[topicIndex];
}
Function name AddTag() goes against the usual convention of camel case naming for functions.

Add Item after NTH element with ion-item

I would like to add an image after every 8 items. This image would be the only item in the ion-item element. This image is not part of the items array and come from another array.
I'm using this (simplified) code:
<ion-list>
<ion-item *ngFor="let item of items; let i = index" (click)="goTo()>
<img src="{item.image}}">
<h2>{{ item.name }}</h2>
</ion-item>
</ion-list>
How could I insert an image every 8 items ?
You can use the index of the ngFor and the modulo operator to achieve that. Please take a look at this working StackBlitz project (the demo uses Ionic 3 but the logic is exactly the same for Ionic 4).
In the following code I just created two list to have some items to show in the view:
Component
import { Component } from '#angular/core';
#Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
public items = [];
public otherImages = [];
constructor() {
// Prepare some items
for(let i = 1; i < 30; i++) {
this.items.push({
name: `Item ${i}`,
image: `https://via.placeholder.com/160x160?text=Item+${i}`
});
}
// Prepare some extra images
for(let j = 1; j < 5; j++) {
this.otherImages.push({
image: `https://via.placeholder.com/160x160?text=Another+Image+${i}`
});
}
}
}
Template
<ion-header>
<ion-navbar>
<ion-title>Home</ion-title>
</ion-navbar>
</ion-header>
<ion-content padding>
<h2>Welcome to Ionic!</h2>
<ion-list>
<ng-container *ngFor="let item of items; let i = index">
<ng-container *ngIf="i > 0 && i % 8 === 0; else noImage">
<!-- First show the image -->
<ion-item *ngIf="i >= 8 && otherImages[i / 8 - 1]">
<img [src]="otherImages[i / 8 - 1].image">
</ion-item>
<!-- Then show the item -->
<ion-item>
<img [src]="item.image">
<h2>{{ item.name }} </h2>
</ion-item>
</ng-container>
<ng-template #noImage>
<!-- Only show the item -->
<ion-item>
<img [src]="item.image">
<h2>{{ item.name }}</h2>
</ion-item>
</ng-template>
</ng-container>
</ion-list>
</ion-content>
In the code above, the first *ngFor="let item of items; let i = index" just goes through the list of items in the items array.
Then we can check the index to see if i > 0 && i % 8 === 0 which means that the current index is the 8th, 16th, 24th,... element of the array.
Since arrays are zero based, the index 8 means the 9th element. This means that we need to show first the extra image, and then the 9th element from the items array.
Please notice that in order to get the right image from the otherImages array, we need to get the index doing: otherImages[i / 8 - 1].image.
<ng-container *ngIf="i > 0 && i % 8 === 0; else noImage">
<!-- First show the image -->
<ion-item *ngIf="i >= 8 && otherImages[i / 8 - 1]">
<img [src]="otherImages[i / 8 - 1].image">
</ion-item>
<!-- Then show the item -->
<ion-item>
<img [src]="item.image">
<h2>{{ item.name }} </h2>
</ion-item>
</ng-container>
If the index is different, we just need to show the item:
<ng-template #noImage>
<!-- Only show the item -->
<ion-item>
<img [src]="item.image">
<h2>{{ item.name }}</h2>
</ion-item>
</ng-template>

Categories

Resources