Using Ionic 3 Framework and components, attributes, properties only (no media queries if possible), does someone know how to define a responsive grid based on screen-orientation?
I want the layout to be displayed in one column when screen-orientation is "portrait" and in two columns when screen-orientation is "landscape", no matter what the screen size is.
I did it using the showWhen attribute like below but it makes me duplicate the code contained in each <ion-col>.
Is there any better solution?
<ion-grid>
<ion-row>
<ion-col showWhen="portrait" col-12>
...[content_1]...
</ion-col>
<ion-col showWhen="landscape" col-6 push-6>
...[content_1]...
</ion-col>
<ion-col showWhen="portrait" col-12>
...[content_2]...
</ion-col>
<ion-col showWhen="landscape" col-6 push-6>
...[content_2]...
</ion-col>
</ion-row>
</ion-grid>
found ! Using the screen-orientation plugin. That's better because I don't have to duplicate the code like my previous solution.
<ion-grid>
<ion-row>
<ion-col [attr.col-12]="screenOrientation.type == 'portrait-primary' ? true : null" [attr.col-6]="screenOrientation.type == 'landscape-primary' ? true : null" [attr.push-6]="screenOrientation.type == 'landscape-primary' ? true : null">
...[content_1]...
</ion-col>
<ion-col [attr.col-12]="screenOrientation.type == 'portrait-primary' ? true : null" [attr.col-6]="screenOrientation.type == 'landscape-primary' ? true : null" [attr.pull-6]="screenOrientation.type == 'landscape-primary' ? true : null" >
...[content_2]...
</ion-col>
</ion-row>
</ion-grid>
screen-orientation type can be known using the screen-orientation plugin
https://ionicframework.com/docs/native/screen-orientation/
if there is only one row:
<ion-grid>
<ion-row>
// show columns in the row depending on what screen-orientation type
<div *ngFor="let content of contents">
<ion-col *ngIf="screen-orientation-type = 'portrait'" col-6>
<div text-wrap [innerHtml]="content.title"></div>
<div text-wrap [innerHtml]="content.body"></div>
</ion-col>
<ion-col *ngIf="screen-orientation-type = 'landscape'" col-12>
<div text-wrap [innerHtml]="content.title"></div>
<div text-wrap [innerHtml]="content.body"></div>
</ion-col>
</div>
</ion-row>
</ion-grid>
if you are getting the contents from a server, create an api that will return content values
or set your content list in the ts
contents:[
{
title?: string,
body?: string
},
{
title?: string,
body?: string
}
];
in same ts file under constructor:
this.contents = [
{
title: '<h1>Content 1</h1>',
body: '<p>Body here</p>'
},
{
title: '<h1>Content 2</h1>',
body: '<p>Body here</p>'
}
]
Related
I am learning ionic. So i have added data to an array declared in a service. When i go back to the lists page, ngOnInit will not execute if i have been to that page before. To load the data i need to use ionViewWillEnter or ionViewDidEnter. However, when i move the function call to the ionViewWillEnteri get the following error:
ERROR TypeError: Cannot read property '0' of undefined
at DiscoverPage_Template (template.html:39)
at executeTemplate (core.js:9544)
at refreshView (core.js:9413)
at refreshComponent (core.js:10579)
at refreshChildComponents (core.js:9210)
at refreshView (core.js:9463)
at refreshEmbeddedViews (core.js:10533)
at refreshView (core.js:9437)
at refreshComponent (core.js:10579)
at refreshChildComponents (core.js:9210)
The only way i can get rid of the above error is by calling the function in both ngOnInIt and ionViewWillEnter.
loadedPlaces: Place[];
listedLoadedPlaces: Place[]; //for virtual scroll
constructor(private placesService: PlacesService, private menuCntrl: MenuController) { }
ngOnInit() {
console.log('ngOnInIt');
this.loadData();
}
ionViewWillEnter(){
console.log('ionViewWillEnter');
this.loadData();
}
loadData(){
this.loadedPlaces = this.placesService.places; //getter property
//for the virtual scroll
this.listedLoadedPlaces = this.loadedPlaces.slice(1);
}
I have also tried declaring an empty array and then removing the function call from ngOnInit. In this case i get following issue:
core.js:6157 ERROR TypeError: Cannot read property 'title' of undefined
at DiscoverPage_Template (template.html:39)
at executeTemplate (core.js:9544)
at refreshView (core.js:9413)
at refreshComponent (core.js:10579)
at refreshChildComponents (core.js:9210)
at refreshView (core.js:9463)
at refreshEmbeddedViews (core.js:10533)
at refreshView (core.js:9437)
at refreshComponent (core.js:10579)
at refreshChildComponents (core.js:9210)
My environment
node: v14.15.5
npm: 6.14.11
angular: 11.2.0
ionic: 6.13.1
How can i solve this issue?
Update:HTML
<ion-header>
<ion-toolbar>
<!--menu drawer-->
<ion-buttons slot="start">
<ion-menu-button menu="menu1"></ion-menu-button>
</ion-buttons>
<ion-title>Discover Places</ion-title>
</ion-toolbar>
</ion-header>
<ion-content class="ion-padding">
<ion-segment value="all" (ionChange)="segmentChanged($event)">
<ion-segment-button value="all">All Places</ion-segment-button>
<ion-segment-button value="bookable">Bookable Places</ion-segment-button>
</ion-segment>
<ion-grid>
<!--open the side drawer manually -->
<ion-row>
<ion-button fill="clear" (click)="onMenuDrawerOpen()">
Menu
<ion-icon slot="start" name="apps-outline"></ion-icon>
<ion-icon slot="end" name="checkmark-done-outline" color="primary"></ion-icon>
</ion-button>
</ion-row>
<!--Featured place-->
<ion-row>
<ion-col size="12" size-sm="8" offset-sm="2" class="ion-text-center">
<ion-card>
<ion-card-header>
<ion-card-title>{{ loadedPlaces[0].title }}</ion-card-title>
<ion-card-subtitle>{{ loadedPlaces[0].price | currency }} / Night</ion-card-subtitle>
</ion-card-header>
<ion-img [src]="loadedPlaces[0].imageUrl"></ion-img>
<ion-card-content>
<div>{{ loadedPlaces[0].description}}</div>
</ion-card-content>
<div class="ion-text-right">
<!--fill Clear mean no background -->
<ion-button fill="clear" color="primary" routerDirection="forward" [routerLink]="['/', 'places', 'tabs', 'discover', 'place', loadedPlaces[0].id, 'detail']">
More
<ion-icon slot="start" name="star"></ion-icon>
<ion-icon slot="end" name="arrow-forward-circle-outline" color="primary"></ion-icon>
</ion-button>
</div>
</ion-card>
</ion-col>
</ion-row>
<!--Other places-->
<ion-row>
<ion-col size="12" size-sm="8" offset-sm="2" class="ion-text-center">
<!--since using scroll, removed the for loop from the ion-item moved it to the ion-virtual-scroll-->
<!--it takes the items property -->
<!--get the approxItemHeight using the dev tools and picking the height of an ion-item. The default is 40px-->
<ion-virtual-scroll [items]="listedLoadedPlaces" approxItemHeight="60px">
<!--<ion-list>-->
<!--Excluding the featured item above-->
<!--<ion-item *ngFor="let place of loadedPlaces.slice(1); let i = index" [routerLink]="['/', 'places', 'tabs', 'discover', 'place', place.id, 'detail']" detail>-->
<ion-item [routerLink]="['/', 'places', 'tabs', 'discover', 'place', place.id, 'detail']"
detail
*virtualItem="let place">
<ion-thumbnail slot="start">
<ion-img [src]="place.imageUrl"></ion-img>
</ion-thumbnail>
<ion-label>
<h2>{{ place.title}}</h2>
<p>{{ place.description }}</p>
</ion-label>
</ion-item>
<!--</ion-list>-->
</ion-virtual-scroll>
</ion-col>
</ion-row>
</ion-grid>
</ion-content>
I had to check for the null. Changing to following fixed the issue, did it for all the properties:
loadedPlaces[0]?.title
<ion-item>
<ion-input type="text" placeholder="My Qr Data" [(ngModel)]="qrData"></ion-input>
</ion-item>
<button ion-button full (click)="createCode()"><ion icon name="barcode"></ion>Create Code</button>
<button ion-button full (click)="scanCode()"><ion icon name="qr-scanner"></ion>Scan Code</button>
<ion-card *ngIf="createdCode">
<ngx-qrcode [qrc-value]="createdCode"></ngx-qrcode>
<ion-card-content>
<p>Value : {{createdCode}}</p>
</ion-card-content>
</ion-card>
<ion-card *ngIf="scannedCode">
<ion-card-content>
Result from Scan: {{scannedCode}}
</ion-card-content>
</ion-card>
Homepage.ts
qrData= null;
createdCode=null;
scannedCode=null;
constructor(private BarcodeScanner:BarcodeScanner) {
}
createCode(){
this.createdCode =this.qrData;
}
scanCode(){
this.BarcodeScanner.scan().then(barcodeData => {
this.scannedCode = barcodeData.text;
})
I am using the qr code generator but it shows the value as text? I can't see it as qr code. Displays the generated Code as text
EDIT: adding a stackblitz:
https://stackblitz.com/edit/ionic-b2r7si
I am using ion-slides as following:
<ion-slides class="fullWidth" [options]="slideOptsOne" #slideWithNav
(ionSlideDidChange)="change($event)">
<ion-slide #status *ngFor="let array of arrays">
<ion-col>
{{array}}
</ion-col>
</ion-slide>
</ion-slides>
I need to change the css style of the current active slide, like make it underlined or bold. I've done some researches and apparently I should use [ngClass]='' but can't know how.
I am getting the index of the active slides using:
change(e) {
this.slides.getActiveIndex().then(
(index) => {
this.currentIndex = index;
console.log(this.currentIndex);
}
)
}
I tried:
<ion-slide #status *ngFor="let array of arrays;let i=index;">
<ion-col [ngClass]="{'activeIndex': currentIndex==array[i]}">
{{array}}
</ion-col>
</ion-slide>
And activeIndex style:
.activeIndex{
font-size: 1.5em;
}
But only one element of the array is changed of style.
Set the activeIndex class to currentIndex === i. If you set it to array[i], you will get letters of the array instead of the index number you are looking for.
<ion-col [ngClass]="{'activeIndex': currentIndex === i}">
{{ array }}
</ion-col>
Working stackblitz
Im Using Ionic3.I want to change my ion-card background color whenever the click function fires, i have some problem it does not work for me, any help on this would be great.Thank You
Thanks
html
<ion-card [color]="buttonColor" (click)="someAction()" tappable>
<ion-card-content >
<p class="item-nme">01.Account Creation Success</p>
<div item-end class="item-mark"><img src="../assets/imgs/checked.png"></div>
</ion-card-content>
</ion-card>
.ts
export class WelcomePage {
private buttonColor: string = "primary";
someAction() {
this.buttonColor = "light";
}
}
you need to use ngStyle or style.background. ion-card doesn't have direct color attribute.
<ion-card [ngStyle]="{'background':buttonColor}" (click)="someAction()" tappable>
<ion-card-content >
<p class="item-nme">01.Account Creation Success</p>
<div item-end class="item-mark"><img src="../assets/imgs/checked.png"></div>
</ion-card-content>
</ion-card>
Using style:
<ion-card [style.background]="buttonColor" (click)="someAction()" tappable>
<ion-card-content >
<p class="item-nme">01.Account Creation Success</p>
<div item-end class="item-mark"><img src="../assets/imgs/checked.png"></div>
</ion-card-content>
</ion-card>
In my app I have variable of String. Which is have in string name of attribute to add.
ngOnInit()
{
this.colAttibute = 'width-50';
}
or it can be equal to 'width-100'. My app is get device width and set the value of this variable on onNgInit method.
I want to set this attribute to my html code something like that:
<ion-list no-lines *ngIf="list">
<ion-list-header>
Лидеры продаж
</ion-list-header>
<ion-item class="categoryProductItem" *ngFor="let row of list;">
<ion-row wrap >
<ion-col *ngFor="let product of row" $colAttibute > <!--Here must be width-50 or width-100 attribute-->
<a ion-item detail-push (click)="onSelectItem(product)" >
<div class="categoryProductItemImage" *ngIf="product.getMainImage()">
<ion-img [src]="product.getMainImage()['small_url']"></ion-img>
</div>
<h2>
{{product.title}}
</h2>
</a>
</ion-col>
</ion-row>
</ion-item>
</ion-list>
How to do this?
You can set the width like this:
<ion-col [attr.width-70]="flag">
Where flag is a boolean value indicating whether to apply this attribute or not.
Unfortunately, you will need to list all the available attributes in order to support all of them dynamically.