How to write if/else in ionic html page? - html

I made an Ionic WordPress app that gives me an error every time a post is published without a featured photo.
What I'm trying to do is filter out those posts that doesn't have a photo but I don't know how to use if/else condition in Ionic.
This is the code for home.html
<ion-card *ngFor="let item of items">
<img src="{{item._embedded['wp:featuredmedia'][0].media_details.sizes.thumbnail.source_url}}"/>
<ion-card-content>
...
</ion-card-content>
</ion-card>

If you're trying to remove items from items that don't have a thumbnail, it's better to do it on the backend when you get them.
this.items = this.items.filter(function(item) {
return (item &&
item._embedded &&
item._embedded['wp:featuredmedia'] &&
item._embedded['wp:featuredmedia'][0] &&
item._embedded['wp:featuredmedia'][0].media_details &&
item._embedded['wp:featuredmedia'][0].media_details.sizes &&
item._embedded['wp:featuredmedia'][0].media_details.sizes.thumbnail &&
item._embedded['wp:featuredmedia'][0].media_details.sizes.thumbnail.source_url);
});
If you want to get every item, thumbnail or no, but hide the thumbnail if it doesn't exist, use *ngIf on your img tag.
<ion-card *ngFor="let item of items">
<img *ngIf="item &&
item._embedded &&
item._embedded['wp:featuredmedia'] &&
item._embedded['wp:featuredmedia'][0] &&
item._embedded['wp:featuredmedia'][0].media_details &&
item._embedded['wp:featuredmedia'][0].media_details.sizes &&
item._embedded['wp:featuredmedia'][0].media_details.sizes.thumbnail &&
item._embedded['wp:featuredmedia'][0].media_details.sizes.thumbnail.source_url"
src="{{item._embedded['wp:featuredmedia'][0].media_details.sizes.thumbnail.source_url}}"/>
</ion-card>
Note: The reason you should check each layer of the object is because if any one of them is missing, you'll get a TypeError saying "could not find property X of undefined".

Related

Angular - How to display single "no results" message on no results

I'm having trouble coming up with a way to show my "no results" div element. Basically, I have a list component containg order timeline section components, each one of these section contains order components. Like so:
My orders-list.component.html (check bottom div):
<div class="list-container" [ngClass]="{section: isDeliverySlotsActive === false}">
<label class="list-header" *ngIf="isDeliverySlotsActive === true" style="margin-top: 1.625rem">DELIVERY SLOTS ORDERS</label>
<div [ngClass]="{section: isDeliverySlotsActive === true}" *ngFor="let date of timelines">
<app-orders-list-section
[orders]="orders"
[timeline]="date"
[isDeliverySlotsActive]="isDeliverySlotsActive"
[searchTerm]="searchTerm"
></app-orders-list-section>
</div>
</div>
/* I want to show the below div when there are no results for the search */
<div id="no-results">
<img src="../../../assets/my-orders/no-results.png" alt="No Results" style="margin-top: 6.063rem; margin-bottom: 2.837rem;">
<label class="no-results-text">COULDN'T FIND ANYTHING</label>
<label class="no-results-text weight-medium">Search by order number or customer</label>
</div>
For each section, a filtering method is applied when the user searches for an order using the search bar. If the search term does not correspond to an order in a section, the order is not displayed for that section. If there are no results for that section the section header is also not displayed.
My orders-list-section.component.html:
<div *ngIf="filteredSectionOrders.length > 0">
<label
*ngIf="isDeliverySlotsActive === true"
[ngClass]="{ slots: isDeliverySlotsActive === true }">
{{ timeline | addSectionDateFormat }}
</label>
</div>
<div *ngFor="let order of filteredSectionOrders">
<app-orders-list-item
[order]="order"
[timeline]="timeline"
></app-orders-list-item>
</div>
My filter method in the section component:
filterSectionOrders(searchString: string){
if(!searchString) return;
if(this.hasNumbers(searchString)){
this.filteredSectionOrders = this.filteredSectionOrders.filter(order => order.order_num.toString().indexOf(searchString) !== -1);
}
else{
this.filteredSectionOrders = this.filteredSectionOrders.filter(order => {
if(order.first_name && order.last_name){
let fullName = order.first_name + " " + order.last_name;
if(fullName.toLowerCase().indexOf(searchString.toLowerCase()) !== -1){
return order;
}
}
})
}
}
Given that I apply this filter to each section and not to the list as a whole, how can I find out when there are 0 total results so I can show only one (not for each section) div element with a "no results found" message?
Thank you in advance.
You can easily use *ngIf;else link to ngIf from angular inside your HTML
I am not sure where do you use filteredSectionOrders, because it is not shown in your html, but let's assume your app-orders-list-section has some HTML logic where you use *ngFor to loop through orders and show it properly
so, I guess your code looks something like this
<div class="order" *ngFor="let order of filteredSectionOrders">
<img/>
<p>
{{ order.first_name + ' ' + order.last_name }}
</p>
</div>
This is simplified html how I assume it looks like.
What you can do is next:
<ng-template *ngIf="filteredSectionOrders.length > 0; else noResultsBlock">
// here you insert your code to render orders
<div class="order" *ngFor="let order of filteredSectionOrders">
<img/>
<p>
{{ order.first_name + ' ' + order.last_name }}
</p>
</div>
</ng-template>
<ng-template #noResultsBlock>
<p> No results </p>
</ng-template>
So, this would simple solution
If you want to improve it even more, it would be better to have a new variable, lets say areThereResults, which you will set to true or false, at the end of your method filterSectionOrders, based on filterSectionOrders.length. Then, you would use this new variable inside *ngIf check, instead of filterSectionOrders.length > 0.
Reason for using boolean variable instead of using actual array is detection changes, and will anguar re-render UI inside *ngIf. You can read more about it on Angular documentation, just search for detection changes.

How to remove the image element from DOM when 403 error occurs in Angular

Is there a way I can remove the entire image element from DOM when 403 error occurs to that image while fetching it from the API so that the title of the card is expanded to the whole width of the card.
This is what I tried so far
HTML
<div *ngFor="let item of items">
<ion-row>
<ion-col>
<div>{{ item.title }}</div>
</ion-col>
<ion-col size="4" class="ion-text-center">
<img src="{{ item.imageurl }}" (error)="handleImageError($event)" />
</ion-col>
</ion-row>
</div>
TS
handleImageError(e) {
e.target.style.display = 'none';
}
I have created a working example using StackBlitz. Could anyone please help.
You are looking for *ngIf on image container, as it removes / adds the element from the DOM. And you will also have to slightly modify the handleImageError.
StackBlitz
<div *ngFor="let item of items">
<ion-row>
<ion-col>
<div>{{ item.title }}</div>
</ion-col>
<ion-col *ngIf="!item.hide" size="4" class="ion-text-center">
<img [src]="item.imageurl" (error)="handleImageError(item)" />
</ion-col>
</ion-row>
</div>
And then in the script, in the handleImageError - do this:
items = [
{imageUrl: '5353ssa.png'},
{imageUrl: 'https://latam.kaspersky.com/content/es-mx/images/product-icon-KSOS.png'},
{imageUrl: '5353ssa.png'},
{imageUrl: '5353ssa.png'},
]
handleImageError(image) {
image.hide = true;
}
Your problem is about your container. U have two columns. Then u will hide column instead of image. U can use ngIf
https://stackblitz.com/edit/ionic-a5wy8u
<ion-col *ngIf="!car.isSHOW">
<ion-card-content>
<img src="{{car.url}}" (error)="handleImageError(car)">
</ion-card-content>
</ion-col>
in component change its to true
handleImageError(e) {
e.isSHOW = true;
}
I would suggest you to use ngIf to hide the complete image, the way I would have address this is
Create a boolean variable at the top of your component.
let shouldHide = false;
Use this variable and ngIf at your image, you can use this at the container level or the image level itself like.
<img src="{{ imageurl }}" (error)="handleImageError($event)" *ngIf="shoudHide"/>
Assign true in case of error
handleImageError(e) {
e.target.style.display = 'none';
this.shouldHide = true;
}
Hope it helps

Color from cards are not changing after event is fired

So I've a problem where I want to change colors from my cards everytime a customer get subscribed to a gym class. ( Red for already subscribed, yellow when is open to subscription)
The problem I'm getting is, anytime when I make a subscription to one class, all the elements from the array, got the color red, instead of one.
So I've an array of classes(named fechaClases) which looks like this:
My HTML code looks like this:
<ion-card color="light" *ngFor="let fecha of fechaCards">
<ion-item color="warning">
<ion-icon slot="start" name="fitness"></ion-icon>
<ion-label>
<h2 style="font-weight: bold">{{ fecha | date:'d/MMMM/yyyy' | uppercase }}</h2>
</ion-label>
</ion-item>
<!-- CONTENIDO --> ---> **Here is where I want to change colors**
<ion-card-content>
<ng-container *ngFor="let clase of fechaClases">
<ion-item [color]="getColor()" (click)="inscripcion(clase)" *ngIf="clase.horaCierre == fecha">
<h2 slot="start" style="font-weight: bold">{{ clase.horaApertura | date: 'shortTime' }}</h2>
<h2 slot="end">{{ "Cupos disponibles" + " " + clase.cuposDisponibles + "/" + clase.cupos }}</h2>
</ion-item>
</ng-container>
</ion-card-content>
</ion-card>
getColor()
for (let index = 0; index < this.fechaClases.length; index++) {
if (this.fechaClases[index].estaInscripto == true) {
console.log(this.fechaClases[index].estaInscripto, 'true');
return 'danger'
}
else {
return 'warning'
}
}
what i'm doing wrong? Hope anyone can help me :) Thanks in advance guys!
You should think in a more "angular" way.
Your list is created by iterating over your fechaClases array, using the *ngFor directive. You just need a conditional binding of the color property, checking the estaInscripto property of each array object.
So, change this line:
<ion-item [color]="getColor()" (click)="inscripcion(clase)" *ngIf="clase.horaCierre == fecha">
with this one:
<ion-item [color]="clase.estaInscripto? 'danger' : 'warning'" (click)="inscripcion(clase)" *ngIf="clase.horaCierre == fecha">
Also, delete your getColor() function, there is no need for it.
Check this stackblitz (inside the home page .html and .ts files) with simplified, working example of the above.
https://stackblitz.com/edit/ionic-e7pfdz

Angular 4 Material 2 - How to change tabbing from being vertical to horizontal with MD-Gridlist?

I'm currently attempting to switch the tabbing inside of an MD-Gridlist to tab hoizontally rather than vertically. I have tried using tab indexes and had no luck. I want to be able to tab through this dynamically growing or shrinking grid list horizontally.
<ng-container *ngFor="let field of fieldsTable; let i = index">
<!--condition in the grid-list tag checks if the key filed can be shown -->
<md-grid-list class="static-column" cols="1" rowHeight="25px" *ngIf="field.$type == GlobalVariables.typeClasses.Static && (field.Name !== '' || showKey)">
<md-grid-tile class="field-name-tile theme-primary" *ngIf="!field.IsKey;">
{{field.Name}}
</md-grid-tile>
<md-grid-tile class="field-name-tile theme-primary" *ngIf="field.IsKey && showKey" mdTooltip="Key field used to update data for this row via the api, values must be unique.">
<md-icon>vpn_key</md-icon>
</md-grid-tile>
<md-grid-tile class="static-field-tile theme-accent-alternating " *ngFor="let content of field.ContentData; let i = index">
<md-input-container class="content-data-input">
<input class="field-input" mdInput (keyup)="content.Value=$event.target.value" value="{{content.Value}}">
</md-input-container>
</md-grid-tile>
</md-grid-list>
</ng-container>
Any help would be greatly appreciated because I've hit a roadblock.
Thank you in advance!
I managed to remedy this by:
Adding this to the input container html which live in the grid tiles of the grid list
tabindex={{setTabIndex(i,j)}}
and this in the TypeScript
setTabIndex(outerIndex: number, innerIndex: number): number {
return (outerIndex + 1) + (innerIndex * this.staticTableLength);
}

Ionic2 view is not updating + Video

i have the following problem, my View isnt updating like it should be. If a player did his move the triggers work (i did a console log on every update of the current game [1]), but the View isnt updating regulary. So i tried to investigate this issue and added in Game.html [2] in the footer a Random number that should be updated every second [3] tocheck if the View is updating correctly. But it didnt, so i console logged every time the random value should change that worked..
My whole Gamelogic is working, if i click on a not valid Tile nothing happens, if i hit on a valid Tile Firebase is updating and sometimes both Players views are aswell.. Some times one view updates, sometimes none updates Video of this issue:
You should take a look at the footer and on that both players should have the same view of the game (besides who's turn it is and the random footer number)
https://youtu.be/Wa-P4tXh6Oo
Grey Field == Valid Field to click on
[1] Checking for Updates
checkForUpdate(key): void {
const query = firebase.database().ref("/games").child(key);
query.on('value', snap => {
console.log("update");
if (!snap.val()) return;
this.updateTurn(snap.val().turn);
this.updatewon_Fields(snap.val().won_fields);
this.updateFields(snap.val().fields);
this.updateNextField(snap.val().nextField);
});
}
I use this Game.html for Singleplayer (vs Bot), Multiplayer (2 Players on one Device) and for Multiplayer (Online). The issue just happens in the Online Multiplayer. Even tho the Data comming in is correct its not updating the view like it should
[2]
Game.html
<ion-content padding>
<ion-grid [ngClass]="getPlayerTurnClass()">
<ion-row *ngFor="let tetrisIndex of index; let r = index; trackBy: trackByFn">
<ion-col *ngFor="let x of tetrisIndex; let x = index; trackBy: trackByFn" [ngClass]="getClassValue(x)">
<div [ngClass]="{'player1_won':gameStatus.won_fields[x]==1,'player2_won':gameStatus.won_fields[x]==2,'bordern':x%2==0,'bordernplus1':x%2!=0}">
<ion-row class="ctr fc tile" *ngFor="let y of index2; let y = index; trackBy: trackByFn">
<ion-col *ngFor="let z of index2; let z = index; trackBy: trackByFn" (click)="playerClick(x,y,z)">
<div class="tile fc">
<span class="ctr tile-text" [ngClass]="{'player1':gameStatus.fields[x][y][z]==1,'player2': gameStatus.fields[x][y][z]==2}">{{(gameStatus.fields[x][y][z]==0)? ' ': ((gameStatus.fields[x][y][z]==1)? 'x' : 'o')}}</span>
</div>
</ion-col>
</ion-row>
</div>
</ion-col>
</ion-row>
</ion-grid>
<div *ngIf="gameService.isGameOver()">
<br>
<button ion-button (click)="btnRestartGame()" full block>Restart Game</button>
<button ion-button (click)="btnReturn()" full block>Return</button>
</div>
<div *ngIf="!gameService.isGameOver()&&gameStatus.gameType&&gameStatus.symbol==gameStatus.turn" class="ctr tile-text"><br><strong>Your turn!</strong><br></div>
<div *ngIf="!gameService.isGameOver()&&gameStatus.gameType!=2" class="ctr tile-text" [ngClass]="{'player1': gameStatus.turn,'player2': !gameStatus.turn}"><br><strong>{{gameStatus.turn? gameStatus.players[0].name : gameStatus.players[1].name}}'s turn!</strong><br></div>
<ion-footer>
<ion-toolbar>
<ion-title>Footer{{gameStatus.random}}</ion-title>
</ion-toolbar>
</ion-footer>
</ion-content>
[3]Gamestatus
setInterval(() => {
this.random = Math.random();
}, 500);
I already tried to add v in Game.ts
setTimeout(() => {
this._applicationRef.tick();
}, 200);
Sorry for my bad english, i hope my question was somewhat clear.Have a great weekend!
In order for something to trigger change detection it needs to be executed
within Angular’s zone.
Try this-
import { NgZone } from '#angular/core';
constructor(public zone: NgZone) {
this.zone.run(() => {
this.updateTurn(snap.val().turn);
this.updatewon_Fields(snap.val().won_fields);
this.updateFields(snap.val().fields);
this.updateNextField(snap.val().nextField);
});
}