CheckBox Function calling a button with IONIC 2 - ionic-framework

I'm simulating something like a shopping cart using ionic 2. Basically you write the item's name and value and it's creating a list with checkbox as in the image below.
But I wanted the option only appear when selecting one of the checkboxes, and did not stay static on the screen as it is now. How can I do this?
grid calling the CheckBox:
<ion-grid>
<ion-row *ngFor="let item of produto">
<ion-item>
<ion-label (click)="clicou(item.desc)">
{{ item.desc }} {{ item.valor }}
</ion-label>
<ion-checkbox checked="false"></ion-checkbox>
</ion-item>
</ion-row>
</ion-grid>
button code part:
<button ion-button block (click)="remove()" color="danger" style="transition: none 0s ease 0s;">
<span class="button-inner">
<ion-icon name="close"></ion-icon>
Remover Selecionados
</span>
<div class="button-effect"></div>
</button>

in ts create a variable that contains the value of the checks, as an example I will use productState which will be boolean type, and create in produto a state.
you can use a ngmodel and the variable already created (productState) to validate the status of the product, and use the event (ionchange) to this
<ion-grid>
<ion-row *ngFor="let item of produto">
<ion-item>
<ion-label (click)="clicou(item.desc)">
{{ item.desc }} {{ item.valor }}
</ion-label>
<ion-checkbox (ionChange)="validState()" [(ngModel)]="productState" ></ion-checkbox>
</ion-item>
</ion-row>
in ts create a function to valid the state of products:
validState(){
let cont = 0;
for (let index = 0; index < this.produto.length; index++) {
if (this.produto[index].State){
cont++;
}
}
if(cont >=1){
this.productState = true;
}else{
this.productState = false;
}
}
and in the button we will use ngIf to validate the product status through productState
<button *ngIf="productState" ion-button block (click)="remove()" color="danger" style="transition: none 0s ease 0s;">
<span class="button-inner">
<ion-icon name="close"></ion-icon>
Remover Selecionados
</span>
<div class="button-effect"></div>
</button>
ngIf docs
ngmodel docs

Related

Ionic 6 ionViewWillEnter cannot read property 0 of undefined

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

ionic push notification opens page but in page navigation is messed up

Folks:
I have an ionic app that has a page where user can post comments on a story. If a user posts new comment, the comment is displayed in the page. Comments are fetched from a REST API using the "let comment of postComments" fragment with *ngFor.
<ion-content *ngIf="!searchUser" #myContent padding [scrollEvents]="true">
<ion-refresher slot="fixed" (ionRefresh)="reloadPage($event)">
<ion-refresher-content pullingIcon="arrow-dropdown" refreshingSpinner="circles" refreshingText="Refreshing..." >
</ion-refresher-content>
</ion-refresher>
<div class="post-content">
<ion-item lines="none" no-padding>
<ion-avatar slot="start">
<img [src]=" (profileUrl == null) ? 'assets/img/emptyperson.jpg' : profileUrl">
</ion-avatar>
<p class="user-post-text">
<strong>{{
username
}}</strong><span>
{{ description }}
</span>
</p>
</ion-item>
<div class="border"></div>
<ion-item-sliding class="comments-container" *ngFor="let comment of postComments; let i = index; let c = count;" [id]="'slidingItem' + i">
<ion-item no-padding lines="none">
<ion-avatar slot="start">
<img [src]=" (comment.profileUrl == null) ? 'assets/img/emptyperson.jpg' : comment.profileUrl">
</ion-avatar>
<p>
<strong>{{
comment.username
}}</strong>
{{ comment.comment }}
</p>
<ion-button
slot="end"
fill="clear"
(click)="likeButton(comment.id, comment.currentUserLike)"
[disabled]="disableLikeButton"
>
<ion-icon
*ngIf="!comment.currentUserLike"
slot="icon-only"
name="heart-outline"
color="black"
></ion-icon>
<ion-icon
*ngIf="comment.currentUserLike"
slot="icon-only"
name="heart"
color="danger"
></ion-icon>
</ion-button>
<br/>
</ion-item>
<ion-item-options *ngIf="isPostMine && (comment.userId != userdetails.id)">
<ion-item-option color="danger" >
<button color="danger" [disabled]="disableDeleteButton" (click)="removeComment(comment.id,i)"><ion-icon class="inside-icon" name="trash"></ion-icon></button>
</ion-item-option>
<ion-item-option color="primary" >
<button color="primary" (click)="reportOffensive(comment.id,i)"><ion-icon class="inside-icon" name="remove-circle"></ion-icon> </button>
</ion-item-option>
</ion-item-options>
<ion-item-options *ngIf="isPostMine && (comment.userId == userdetails.id)">
<ion-item-option color="danger" >
<button color="danger" [disabled]="disableDeleteButton" (click)="removeComment(comment.id,i)"><ion-icon class="inside-icon" name="trash"></ion-icon></button>
</ion-item-option>
</ion-item-options>
<ion-item-options *ngIf="!isPostMine && (comment.userId != userdetails.id)">
<ion-item-option color="primary" >
<button color="primary" (click)="reportOffensive(comment.id,i)"><ion-icon class="inside-icon" name="remove-circle"></ion-icon> </button>
</ion-item-option>
</ion-item-options>
<ion-item-options *ngIf="!isPostMine && (comment.userId == userdetails.id)">
<ion-item-option color="danger" >
<button color="danger" [disabled]="disableDeleteButton" (click)="removeComment(comment.id,i)"><ion-icon class="inside-icon" name="trash"></ion-icon></button>
</ion-item-option>
</ion-item-options>
<p class="all-comments">
<span class="grey-text"> {{ comment.createdAt | timeAgo }}</span>
<span *ngIf="comment.numLikes > 0" class="grey-text tab" (click)="userList(comment.id,'CommentLikes')">{{comment.numLikes}} likes</span>
</p>
</ion-item-sliding>
</div>
</ion-content>
<ion-footer>
<ion-item lines="none">
<ion-avatar slot="start">
<img src="{{ userProfileUrl }}" />
</ion-avatar>
<ion-textarea autocapitalize="sentences" maxLength="255" type="text"
[(ngModel)]="commentContent" (ionChange)="getUsers($event)"
rows="1"
placeholder="Add a comment"
></ion-textarea>
<ion-icon class="blueicon" slot="end" name="send" (click)="addComment()"></ion-icon>
</ion-item>
</ion-footer>
In my typescript, I have a function addComment() which refreshes the value of postComments so that the page automatically reloads.
addComment() {
if (this.commentContent.trim()) {
this.showLoader("Posting Comment ...");
this.userPostComment.comment = this.commentContent;
this.userPostCommentJSON = JSON.stringify(this.userPostComment);
//console.log("Comment JSON is "+this.userPostCommentJSON);
this.https.post(this.serviceUrl+'comments',this.userPostCommentJSON,this.httpOptions)
.subscribe(
(res: any)=>{
this.commentContent = "";
this.refresh();
setTimeout(() => {
console.log("In Timeout");
this.refreshPostComments("");
this.events.publish('postComment:created', {
id: res.id,
time: new Date()
});
this.hideLoader();
this.commentContent = "";
},2000)
},
err => {
this.hideLoader();
this.showAlert(err);
}
);
}
}
This is working like charm, when I get to the Comments page from the story.
Here is my problem. If I navigate to the Comments page from a oneSignal push notification, everything works fine up to the point where I enter a new comment. When I enter a new Comment, the comment is created in the database using the RESTAPI (works fine), the refreshPostComments method is called in typescript (works fine), but my view does not get updated till I physically click the comment box again.
I don't know what I am doing wrong. But in my app.component.ts, I check for oneSignal notification clicked and if clicked, I do this
if (localStorage.getItem('auth-user') != undefined || null) {
if (additionalData.type == "comment") {
await console.log("Going to Comments");
this.router1.navigateForward(['/comments', {
userId: parseInt(additionalData.userId),
username: additionalData.username,
userPostId: parseInt(additionalData.userPostId),
description: additionalData.description,
profileNameKey: additionalData.profileNameKey
}]);
}
That works. Takes me to the Comments Page. But once I am in the page, I can do virtually everything else like peach, except if I add a comment, then it does not reflect in real time.
Any pointers on what I am missing?
JR
Found my solution. I think Angular’s Change detection is triggered by certain events, and when I was navigating to the page from OneSignal's notification - whatever OneSignal was using, it was not getting on Angular's radar. So I had to import ChangeDetectorRef and do a manual detectChanges() to make sure ngFor would detect the changes as soon as they occur.
Phew. Spent almost a half a day on this. So much for OneSignal and Angular's quirks with OneSignal. And Ionic had nothing to do with it.
Regards,
JR

When there is no text on ion-search bar the list should hide?

i stuck , please help me
I am using ion-searchbar , i want that when there is no text on the searchbar the list must be hide but the list is still showing
Can anyone help me?
in .html file
<ion-searchbar (ionInput)="getItems($event)" class="" style="background-color: #073262 !important" [showCancelButton]="shouldShowCancel" style="background:none!important;"></ion-searchbar>
<ion-list>
<ion-item *ngFor="let item of items" (click)="openNavDetailsPage(item)">
{{ item }}
</ion-item>
</ion-list>
in .ts file
getItems(ev) {
// Reset items back to all of the items
this.initializeItems();
// set val to the value of the ev target
var val = ev.target.value;
// if the value is an empty string don't filter the items
if (val && val.trim() != '') {
this.items = this.items.filter((item) => {
return (item.toLowerCase().indexOf(val.toLowerCase()) > -1);
})
}
}
You can use ngModel and ngIf :
<ion-searchbar [(ngModel)]="searchInput" (ionInput)="getItems($event)" class="" style="background-color: #073262 !important" [showCancelButton]="shouldShowCancel" style="background:none!important;"></ion-searchbar>
<ion-list *ngIf="searchInput !== ''">
<ion-item *ngFor="let item of items" (click)="openNavDetailsPage(item)">
{{ item }}
</ion-item>
</ion-list>
in .ts:
public searchInput='';
OR
If your variable items is empty at initalization :
<ion-searchbar (ionInput)="getItems($event)" class="" style="background-color: #073262 !important" [showCancelButton]="shouldShowCancel" style="background:none!important;"></ion-searchbar>
<ion-list *ngIf="items && items.length">
<ion-item *ngFor="let item of items" (click)="openNavDetailsPage(item)">
{{ item }}
</ion-item>
</ion-list>
in .ts:
public items = [];

Ionic latest add item not display in the list top

Im using ionic 3 for my mobile application. I have an issue with my item list, my issue is when i add a new item it does not show up at the top of the list, it always appears at the bottom , how to do that correctly?
Thanks
example
add Item -
first -A
second-B
its display
A
B
I want to know how can display this type
B
A
item list
<ion-list class="ion-addexe">
<ion-item *ngFor="let bill of Details">
<ion-label>
<p class="ion-lbl" style="position: relative;top:-0.2rem;">{{bill.billdescription}}</p>
</ion-label>
<ion-label>
<p class="ion-lbl" text-right style="position: relative;top:-0.2rem;">$ {{bill.billtotal}}</p>
</ion-label>
</ion-item>
</ion-list>
add item
<div>
<ion-item >
<ion-label id="ion-lbls">Select you want</ion-label>
<ion-select [(ngModel)]="addnewBill_category" okText="Add" cancelText="Close">
<ion-option *ngFor="let bill of Category" value="{{bill.billCategoryID}}">{{bill.CategoryName}}</ion-option>
</ion-select>
</ion-item>
<ion-item >
<ion-label id="ion-lbls">Details</ion-label>
<ion-input type="text" value="" [(ngModel)] = "addnewBill_description" placeholder="Description" text-right></ion-input>
</ion-item>
<ion-item >
<ion-label id="ion-lbls">Date</ion-label>
<ion-datetime displayFormat="MMM DD YYYY" [(ngModel)]="event.addnewbill_Date" placeholder="MMM/DD/YYYY"></ion-datetime>
</ion-item>
<ion-item>
<ion-label id="ion-lbls">Total ($)</ion-label>
<ion-input type="number" [(ngModel)]="addnewBill_amount" value="" placeholder="$0.0" text-right></ion-input>
</ion-item>
</div>
</ion-list>
First of all that is the correct way in which a ngFor works it displays the first element first and the next items at the bottom, because whenever you insert new items inside an array it follows the top to bottom approach. So basically you want to display your array items in reverse order that should be your question
The most simple and easy solution to this is by just using reverse() on your *ngfor. In your case it would be something like this:
<ion-item *ngFor="let bill of Details.reverse()">
...
<ion-item>
or one more solution is using a custom angular pipe which you could apply on the *ngFor and sort your array in reverse order.
import { Pipe, PipeTransform } from '#angular/core';
#Pipe({
name: 'reverse'
})
export class ReversePipe implements PipeTransform {
transform(value) {
if (!value) return;
return value.reverse();
}
}
and then in your html you can use that pipe like this:
<ion-item *ngFor="let bill of Details | reverse">
...
<ion-item>

How to set various attribute of DOM element from variable angular 2?

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.