*ngIf doesn't work with ng-template (ionic 5/angular 9) - angular9

Here is my component.page.ts file
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-domestic',
templateUrl: './domestic.page.html',
styleUrls: ['./domestic.page.scss'],
})
export class DomesticPage implements OnInit {
opchoice: string;
constructor() { }
ngOnInit() {
this.opchoice = "From";
console.log("OnInit opchoice? " + this.opchoice);
}
onFromToChange (ev: any) {
console.log("OnFromToChange");
this.opchoice = ev.detail.value;
console.log("opchoice? >" + this.opchoice + "<");
}
}
and the HTML file.
<ion-content>
<ion-segment value="From" (ionChange)="onFromToChange($event)">
<ion-segment-button value="From">Pickup From</ion-segment-button>
<ion-segment-button value="To">Deliver To</ion-segment-button>
</ion-segment>
<div *ngIf="opchoice=='From'; then ShowFrom else ShowTo">
<ng-template #ShowFrom class="ion-text-wrap ion-no-padding ion-no-margin">
<ion-item>Domestic - Ship From</ion-item>
</ng-template>
<ng-template #ShowTo class="ion-text-wrap ion-no-padding ion-no-margin">
<ion-item>Domestic - Ship To</ion-item>
</ng-template>
</div>
</ion-content>
However, the page doesn't display anything (it is empty) whether I click on the "Pickup From" or "Deliver To" Tabs/buttons.
Is there something I am doing wrong or have not understood about ng-template or ngIf? As you can see, I am printing the value of the opchoice variable and it prints correctly for each type of click. I have tried putting the ngIf in the ion-item, in an ion-grid and many other combinations, but none work.
I am using Ionic 5 with Angular 9. Any help is appreciated.

As I said before, you have to put the ng-templates at the same level. For me the cleanest solution is:
<div class="ion-text-wrap ion-no-padding ion-no-margin">
<div *ngIf="opchoice=='From'; else ShowTo">
<ion-item>Domestic - Ship From</ion-item>
</div>
<ng-template #ShowTo>
<ion-item>Domestic - Ship To</ion-item>c
</ng-template>
</div>

Related

Best practice for abstracting Angular HTML code?

In my Angular project I have a basic component
TS
#Component({
selector: 'app-cardboxes',
templateUrl: './cardboxes.component.html',
styleUrls: ['./cardboxes.component.scss']
})
export class CardboxesComponent implements OnInit {
constructor(public dialog: MatDialog) { }
ngOnInit() {}
}
In the HTML file, I use this component about 16 times. I have it completely hardcoded for 16 different "cardboxes", like so:
HTML
<mat-card id="CARDBOX">
<img class="logoy" src="assets/image" height=35px>
Box1
<input type="image" id="info" title="Click for description" src="assets/image2" height=20px/>
</mat-card>
<mat-card id="CARDBOX">
<img class="logoy" src="assets/image3" height=35px/>
Box2
<input type="image" id="info" title="Click for description" src="assets/image2.png" height=20px/>
</mat-card>
Essentially this renders a little box with a couple images, and a button that takes the user to an external link. There are 16 of these boxes typed into the HTML file, and everytime I want to add a new one, I have to rewrite essentially the same code with only the inputs different.
As you can see this format is heavily reused, but it is arduously hardcoded into the HTML file. Is there a way that I could abstract the reused code so that it is not tediously hardcoded in? How can I make a template for this that can be used multiple times? Going further, how can I add to, remove from, and alter this list of items?
In your component.ts file, you can add a property called something like: cards.
#Component({
selector: 'app-cardboxes',
templateUrl: './cardboxes.component.html',
styleUrls: ['./cardboxes.component.scss']
})
export class CardboxesComponent implements OnInit {
cards = [
{
'imageUrl': '/assets/image.png',
'link': 'link1.com',
... More Stuff YOu like
},
{
'imageUrl': '/assets/image1.png',
'link': 'link1.com',
... More Stuff YOu like
},
.. More items ...
];
constructor(public dialog: MatDialog) { }
ngOnInit() {}
}
Then in your html, you can loop through that cards array:
<mat-card id="CARDBOX" *ngFor="let card of cards">
<img class="logoy" src="{{ card.imageUrl }}" height=35px/>
Box2
<input type="image" id="info" title="Click for description" src="assets/image2.png" height=20px/>
</mat-card>
Note: I would also avoid adding the CARDBOX id to each element, as that is bad practice in HTML5.
Then your problem should be solved ... Let me know if it helps you.
Did not test it, but a ngFor can work wonders in this cases.
Make an array of a new interface cardDetails
export interface CardDetail {
id: number;
image: string;
link: string;
button: string;
input: string;
}
<mat-card *ngFor="let item of cardDetailArray">
<img class="logoy" src="{{item.image}}" height=35px>
{{item.button}}
<input type="image" id="info" title="Click for description" src="{{image.input}}" height=20px/>
</mat-card>
If it's literally only a diff on numbers. just make a number array[1,2,3,...x] and use the ngfor let item in numberArray , concatenate all things with the number variable.

Multiple Select component for Angular with list style

I need a select component like
The problem is they don't have it in Material Angular, so I tried using default HTML select inside the component. It works fine until I tried to destroy the view of the HTML select(for example when you redirect to other page), it will freeze the whole page for a couple of seconds(the larger the list the longer it will freeze).
First, anyone know the reason why Angular takes a while to destroy non material angular component? Then does anyone have a solution whether to make the freeze gone or appoint me to select component library that could be use in Angular perfectly? I really need the support of being able to select multiple items with click + shift
Here's my component code:
HTML:
<div class="chart">
<div class="toolbar">
<div class="row">
<i *ngIf="multiple" (click)="resetFilter()" class="option material-icons left">refresh</i>
<h4>Sample Id</h4>
<span class="option right"></span>
</div>
</div>
<div class="content">
<select *ngIf="!showSampleCSV" [multiple]="multiple" [size]="100" class="samples-list" [(ngModel)]="selectedSamples" (ngModelChange)="onSelect($event)">
<option *ngFor="let sampleID of sampleIDs" [value]="sampleID">{{sampleID}}</option>
</select>
<app-samples-text *ngIf="showSampleCSV" [samples]="selectedSamples" [multiple]="multiple" (filterSamples)="filterCSV($event)"></app-samples-text>
</div>
</div>
TS:
import { Component, OnInit, Input, Output, EventEmitter, ChangeDetectionStrategy, OnDestroy } from '#angular/core';
#Component({
selector: 'app-samples-list',
templateUrl: './samples-list.component.html',
styleUrls: ['./samples-list.component.css'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class SamplesListComponent implements OnInit, OnDestroy {
#Input() sampleIDs : string[] = [];
#Input() showSampleCSV : boolean;
#Input() selectedSamples : string[];
#Output() onSelectSamples = new EventEmitter<string[]>();
#Output() onUpdateSamples = new EventEmitter<string[]>();
#Input() multiple: boolean = true;
size = this.sampleIDs.length;
constructor() { }
ngOnInit() {
}
resetFilter() {
this.onSelectSamples.emit(this.sampleIDs);
}
onSelect(samples){
this.onSelectSamples.emit(samples);
}
filterCSV(samples){
this.onUpdateSamples.emit(samples.map(sample => sample.trim()));
}
ngOnDestroy() {
}
}
Problem illustration on stackblitz https://stackblitz.com/edit/angular-qojyqc?embed=1&file=src/app/app.component.html
Material does provide an option for multi select values
<mat-form-field>
<mat-label>Toppings</mat-label>
<mat-select [formControl]="toppings" multiple>
<mat-option *ngFor="let topping of toppingList" [value]="topping">{{topping}}</mat-
option>
</mat-select>
</mat-form-field>
For more information go Here

How to move Ion-Slides next after every 10 second in Ionic 4?

I'm creating Ionic 4 plus Angular app. In that I'm using Ion-Slides to show number of questions one by one. Now I want move Ion-Slides next after every 10 seconds.
Ionic Slides Documentation
this is the ionic 4 explanation
html.
<ion-slides [options]="slideOpts" >
<ion-slide *ngFor="let item of cars">
<img src="{{item}}" width="400px" height="250px">
</ion-slide>
</ion-slides>
.ts
import { Component, ViewChild } from '#angular/core';
import {IonSlides} from '#ionic/angular';
export class HomePage {
#ViewChild(IonSlides) slides: IonSlides;
cars=[
"https://imgd.aeplcdn.com/1056x594/ec/79/85/9802/img/ol/Lamborghini-Aventador-Front-view-52648.jpg?v=201711021421&q=80",
"https://imgd.aeplcdn.com/1056x594/ec/79/85/9802/img/ol/Lamborghini-Aventador-Right-Front-Three-Quarter-52645.jpg?v=201711021421&q=80",
"https://imgd.aeplcdn.com/1056x594/ec/79/85/9802/img/ol/Lamborghini-Aventador-Right-Side-52646.jpg?v=201711021421&q=80",
"https://imgd.aeplcdn.com/1056x594/ec/79/85/9802/img/ol/Lamborghini-Aventador-Left-Front-Three-Quarter-52647.jpg?v=201711021421&q=80",
"https://imgd.aeplcdn.com/1056x594/ec/79/85/9802/img/ol/Lamborghini-Aventador-Front-view-52649.jpg?v=201711021421&q=80",
"https://imgd.aeplcdn.com/1056x594/ec/79/85/9802/img/ol/Lamborghini-Aventador-Rear-view-52650.jpg?v=201711021421&q=80"
];
ngOnInit(){
this.slides.startAutoplay().then(()=>{})}
}
slideOpts = {
speed: 10000
};
You can grab the component with ViewChild then you can use its methods on page initialisation. startAutoplay() is mentioned in the docs you linked. Slide options allows you to set the speed of transitions. If you want a true solution that flips the slide every 10 seconds you could write an async method which changes the slide every 10 seconds. Comment if you need help.
you can do like this,
.html
<ion-slides #slid autoplay="5000" loop="true" speed="500" pager="true" >
<ion-slide *ngFor="let item of cars">
<img src="{{item}}" width="400px" height="250px">
</ion-slide>
</ion-slides>
.ts
import { Component, OnInit, ViewChild } from '#angular/core';
import { Platform } from 'ionic-angular';
import { TabsPage } from '../pages/tabs/tabs';
#Component({
templateUrl: 'app.html'
})
export class MyApp {
rootPage:any = TabsPage;
cars=[
"https://imgd.aeplcdn.com/1056x594/ec/79/85/9802/img/ol/Lamborghini-Aventador-Front-view-52648.jpg?v=201711021421&q=80",
"https://imgd.aeplcdn.com/1056x594/ec/79/85/9802/img/ol/Lamborghini-Aventador-Right-Front-Three-Quarter-52645.jpg?v=201711021421&q=80",
"https://imgd.aeplcdn.com/1056x594/ec/79/85/9802/img/ol/Lamborghini-Aventador-Right-Side-52646.jpg?v=201711021421&q=80",
"https://imgd.aeplcdn.com/1056x594/ec/79/85/9802/img/ol/Lamborghini-Aventador-Left-Front-Three-Quarter-52647.jpg?v=201711021421&q=80",
"https://imgd.aeplcdn.com/1056x594/ec/79/85/9802/img/ol/Lamborghini-Aventador-Front-view-52649.jpg?v=201711021421&q=80",
"https://imgd.aeplcdn.com/1056x594/ec/79/85/9802/img/ol/Lamborghini-Aventador-Rear-view-52650.jpg?v=201711021421&q=80"
];
}
here is the stackblitz link [https://stackblitz.com/edit/ionic-8qkwca ]

How to get input text value in ionic

I'm trying to get input text value and store it in a variable named input in ionic. But I tried and failed. Can anyone please tell me what I have faulty done?
This is my HTML
<ion-content>
<ion-list>
<ion-item>
<ion-label stacked>display</ion-label>
<ion-input type="text" text-right id="input" ></ion-input>
</ion-item>
</ion-list>
</ion-content>
and this is my home.ts in ionic
import { Component } from '#angular/core';
import { NavController } from 'ionic-angular';
#Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
constructor(public navCtrl: NavController) {
var input=document.getElementById('input').nodeValue;
document.getElementById('seven').innerHTML=input;
}
}
Actually you seems to be using angular not angularjs, use [(ngModel)]
<ion-input type="text" [(ngModel)]="name" text-right id="input" ></ion-input>
and inside the component,
name:string;
so whenever you need the value , you can use.
console.log(this.name);
<ion-content>
<ion-list>
<ion-item>
<ion-label stacked>display</ion-label>
<ion-input type="text" text-right id="input" [(ngModel)]="inputValue"></ion-input>
</ion-item>
</ion-list>
</ion-content>
// ===
import { Component } from '#angular/core';
import { NavController } from 'ionic-angular';
#Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
inputValue: string = "";
constructor(public navCtrl: NavController) {}
someFunction() {
// here you can use the 'this.inputValue' and get the value of the ion-input
}
}
we use the two way binding the value of ion-input with the class member inputValue,
about ngModel
whan you need to access on the value of the input, check the value of inputValue.
here you can see an exemple I wrote on StackBlitz
Two-way binding is a combination of both property binding and event binding as it is a continuous synchronization of data/values from presentation layer to component and from component to the presentation layer.
Since this is a two way binding we have to use both the brackets - [ ( ) ]. Also ngModel is a directive which is used to bind the data both ways.
In Ionic 5 - The way to get the value of an ion-input value when focusing:
<ion-input (ionFocus)="onFocusPlace($event)"></ion-input>
onFocusPlace(event){
this.value = event.target.value;
}

getting errors while displaying json format list in html it cannot be displayed

I am facing some problems while displaying the json formatted data in html file. It work successfully but list is not displayed. This in my code...
import { Component } from '#angular/core';
import { Platform } from 'ionic-angular';
import { Hotspot, Network } from 'ionic-native';
#Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
constructor(public platform: Platform){
this.platform = platform
}
List(){
Hotspot.scanWifi().then((networks:Array<Network>)=>{
console.log(networks);
});
}
}
This is my HTML File
<ion-header>
<ion-navbar>
<ion-title>
Ionic Blank
</ion-title>
</ion-navbar>
</ion-header>
<ion-content padding>
<button ion-button color="Primary" (click)="List()">ScanWifi</button>
<div *ngFor="let network of networks">
<ion-list>
<ion-item>
<h2>{{network}}</h2><br>
</ion-item>
</ion-list>
</div>
</ion-content>
You are just console logging your result, your current code:
List(){
Hotspot.scanWifi().then((networks:Array<Network>)=>{
console.log(networks);
});
You need to declare a local variable networks so that you can use it in the view as you have:
So your code should look something like this:
networks;
List(){
Hotspot.scanWifi().then((networks:Array<Network>)=>{
this.networks = networks;
});
so that you can refer to your networks in your view:
<div *ngFor="let network of networks">
EDIT: I first wrongfully "assumed" that Hotspot needed to be injected into the constructor, but by doing some research, I found out that Hotspot is a native element with methods, and can therefore be called just by Hotspot.scanWifi() as per can be seen here.
You have to set networks array in the class
export class HomePage {
networks:any;
constructor(public platform: Platform){
this.platform = platform
}
List(){
Hotspot.scanWifi().then((networks:Array<Network>)=>{
console.log(networks);
this.networks = networks;//or do forEach and push
});
}
}