Ion-list not refreshing afer model change - angularjs

I am having a problem with the ion-list, I can list all the items when the app loads for the first time, but when I make any changes to it, adding or removing data, the list isn't updating for the user.
I am using Pouch db to add and remove data for persistence in the app, all the functions are working correctly, it can be confirmed through console.log in the contents or using the fauxton PouchDb extension for chrome.
Resuming, the data is changing, but the view is not reflecting it.
the view code is this notas.html
<ion-content>
<ion-list>
<ion-item-sliding *ngFor="let n of notas">
<ion-item>
<h2>{{n.descricao}}</h2>
<p>URL: {{n.endereco}}</p>
<p>Data de expiração: {{n.vencimento}}</p>
</ion-item>
<ion-item-options side="right">
<button ion-button (click)="editar(n)">
<ion-icon name="paper"></ion-icon>
Editar
</button>
<button ion-button color="danger" (click)="excluir(n)">
<ion-icon name="trash"></ion-icon>
Excluir
</button>
</ion-item-options>
</ion-item-sliding>
</ion-list>
</ion-content>
And the controler code is this notas.ts
...
#Component({
selector: 'page-notas',
templateUrl: 'notas.html'
})
export class NotasPage {
notas: any;
constructor(public navCtrl: NavController, public alertCtrl: AlertController, public pouchDBService: PouchdbProvider) {
//PARA USO DO EXTENSION DO CHROME *POUCHDB Fauxton
(<any>window).PouchDB = PouchDB;
this.notas = [];
}
ionViewDidLoad(){
this.refresh();
}
refresh(){
//console.log(this.notas);
this.notas = [];
this.pouchDBService.getData().then((data) => {
this.notas = data;
console.log(this.notas);
});
// console.log(this.notas);
}
excluir(nota){
let prompt = this.alertCtrl.create({
title: 'Excluir',
message: 'Deseja realmente excluir o registro?',
buttons: [
{
text: 'Cancelar'
},
{
text: 'Excluir',
handler: data => {
this.pouchDBService.delete(nota);
this.notas.pop(nota);
this.refresh();
}
}
]
});
prompt.present();
}
}
...

Not 100% sure on this but usually if the view is not updating, it has to do with the code not running on zone, so:
import { NgZone } from '#angular/core';
...
zone: any = new NgZone({ enableLongStackTrace: false });
And then change your refresh method to:
refresh(){
//console.log(this.notas);
this.notas = [];
this.pouchDBService.getData().then((data) => {
this.zone.run(() => {
this.notas = data;
console.log(this.notas);
});
});
// console.log(this.notas);
}
I believe that should work.

Related

Edit Items in a List Using Modal in Ionic 3

I have created an Array and I'm adding items to the array using Modal.
Now i need to edit the item by selecting it from the list.
please help me with the Code.
How to fetch the item to modal and bring back the edited item in the same place in the list
HOME.HTML
<ion-header>
<ion-navbar>
<ion-title>
Ionic Blank
</ion-title>
</ion-navbar>
</ion-header>
<ion-content>
<ion-list>
<ion-item *ngFor="let grocery of itemsArray">{{grocery}}</ion-item>
</ion-list>
<button ion-button round (click)="addItem()">Add Item</button>
</ion-content>
HOME.TS
export class HomePage {
public itemsArray = [];
newItem: any;
constructor(public navCtrl: NavController, public modalCtrl: ModalController, public navParams: NavParams) {
}
ionViewDidLoad() {
this.newItem = this.navParams.get('data');
this.itemsArray = [
];
}
public addItem() {
let modalPage = this.modalCtrl.create(ModalPage);
modalPage.onDidDismiss(data => {
this.itemsArray.push(data.name
);
});
modalPage.present();
}
}
MODAL.HTML
<ion-header>
<ion-navbar>
<ion-title>Add Item</ion-title>
<ion-buttons end>
<button ion-button (click)="closeModal()">Close</button>
</ion-buttons>
</ion-navbar>
</ion-header>
<ion-content padding>
<ion-list>
<ion-item>
<ion-label>Item</ion-label>
<ion-input type="text" [(ngModel)]="newItem"></ion-input>
</ion-item>
<button ion-button color="secondary" (click)="add()">Add Item</button>
</ion-list>
</ion-content>
MODAL.TS
export class ModalPage {
name:any;
newItem: any;
constructor(public navCtrl: NavController, public viewCtrl: ViewController, public navParams: NavParams) {
}
ionViewDidLoad() {
console.log('ionViewDidLoad ModalPage');
}
public closeModal() {
this.viewCtrl.dismiss();
}
//add() {
// let data = {"name": this.newItem};
// this.viewCtrl.dismiss(data.name)
// }
add() {
let data = {"name": this.newItem};
this.viewCtrl.dismiss(data)
}
}
The code untill now works fine.
I would recommend using alert controller to simplify your code in your use case. If you would need a modal - you can elaborate the code later.
Try this approach:
<ion-header>
<ion-navbar>
<ion-title>
Ionic Blank
</ion-title>
</ion-navbar>
</ion-header>
<ion-content>
<ion-list *ngFor="let grocery of itemsArray; let i = index">
<ion-item (click)="changeItemName(grocery, i)">{{grocery}}</ion-item>
</ion-list>
<button ion-button round (click)="addItem()">Add Item</button>
</ion-content>
Place iterator on the list and capture "index" per item, so that you could pass that value if particular item from the list is clicked together with actual grocery item name.
In your home.ts:
import { Component } from '#angular/core';
import { NavController, NavParams, AlertController, ViewController } from 'ionic-angular';
#Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
public itemsArray = ["milk", "butter", "bread"];
newItem: any;
constructor(public navCtrl: NavController, public alertCtrl: AlertController, public navParams: NavParams) {
}
public changeItemName(currentName, index) {
let alert = this.alertCtrl.create({
title: 'Change grocery item name:',
message: 'current: "' + currentName + '"',
inputs: [
{
placeholder: 'type in a new name'
}
],
buttons: [
{
text: 'Cancel',
role: 'cancel',
},
{
text: 'Confirm',
handler: data => {
if (data[0].length === 0) {
this.itemsArray[index] = currentName;
} else {
this.itemsArray[index] = data[0];
}
}
}
]
});
alert.present();
};
public addItem() {
let index = this.itemsArray.length;
this.changeItemName("New item", index);
}
}
You can use alert controller to show a small pop-up with input field. In the code you will see that we pass parameters to it and we modify list item name OR we add item to the list if change name method was called by addItem method.
Let me know if this is helpful for you.
Here is a working snippet: https://stackblitz.com/edit/ionic-urbtag

Array of methods not working ionic 2

I'm working on ionic 2. I've created a menu for my page and an array of contents for menu.
menuItems: Array<{title: string, icon: string, method: any}>
And added elements.
this.menuItems =
[
{title: "Edit Account", icon: "create", method: "editAcount()"},
{title: "Change Password", icon: "create", method: "changePassword()"},
{title: "LogOut", icon: "log-out", method: "logOut()"},
];
And I'm calling methods at run-time.
<ion-item *ngFor = "let item of menuItems" menuClose (click) = "item.method"> <!--like this-->
{{item.title}}
<ion-icon item-end name = "{{item.icon}}"></ion-icon>
</ion-item>
But nothing happens. Methods never get called.
When I do this console.log(item.method) it never shows body, only shows methods names.
same result when I tried interpolation i.e.
<ion-item *ngFor = "let item of menuItems" menuClose (click) = "item.method">
{{item.title}} {{item.method}}<!--methods names only-->
<ion-icon item-end name = "{{item.icon}}"></ion-icon>
</ion-item>
Help me guys.
Here's ts file
import { Component } from '#angular/core';
import { IonicPage, NavController, NavParams, ViewController, MenuController } from 'ionic-angular';
import { HomePage } from "../home/home";
import { EditUsersProvider } from "../../providers/edit-users/edit-users";
import { FlashMessageProvider } from "../../providers/flash-message/flash-message";
#IonicPage()
#Component(
{
selector: 'page-user-account',
templateUrl: 'user-account.html',
})
export class UserAccountPage
{
userContents;
menuItems: Array<{title: string, icon: string, method: any}>;
constructor(
public navCtrl: NavController,
public navParams: NavParams,
public viewCtrl: ViewController,
private editUser: EditUsersProvider,
private flashMsg: FlashMessageProvider,
public menuCtrl: MenuController)
{
menuCtrl.enable(true, "menu");
this.userContents = this.navParams.data;
this.menuItems =
[ //Problem might be here.
{title: "Edit Account", icon: "create", method: "editAcount()"},
{title: "Change Password", icon: "create", method: "changePassword()"},
{title: "LogOut", icon: "log-out", method: "logOut()"},
];
}
editAcount()
{
console.log("It never triggers");
}
changePassword()
{
console.log("It never triggers");
}
logOut()
{
console.log("It never triggers");
}
}
Here's template file
<ion-menu #menu id = "menu" [content] = "content">
<ion-header>
<ion-toolbar>
<ion-title>Menu</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-list>
<ion-item *ngFor = "let item of menuItems" menuClose (click) = "item.method"> <!--this never executes -->
{{item.title}}
<ion-icon item-end name = "{{item.icon}}"></ion-icon>
</ion-item>
</ion-list>
</ion-content>
</ion-menu>
You are setting method property as a string representation of a method call.
It doesn't actually call the method because it is a string literal. The function object (eg: this.editAccount) can be set using arrow function (eg: ()=>this.editAccount())or by using bind() e.g: this.editAccount.bind(this);
Try setting like this:
this.menuItems =
[ //Problem might be here.
{title: "Edit Account", icon: "create", method: () => this.editAcount()},
{title: "Change Password", icon: "create", method: () => this.changePassword()},
{title: "LogOut", icon: "log-out", method: () => this.logOut()},
];
In your template call as:
<ion-item *ngFor = "let item of menuItems" menuClose (click) = "item.method()"> <!--this will execute -->

Angular 2 Reading List with ngFor on View?

I'm trying List reading from WebApi with ngFor but it doesn't work for me.
export class MembershipPage {
memberships: any = [];
constructor(public navCtrl: NavController, public authservice: AuthService) {
}
ionViewDidEnter() {
this.authservice.getmembers().then(
data => {
this.memberships.push(data);
}
);
}
and i'am calling from view like this`
<ion-content>
<ion-list>
<ion-item *ngFor="let member of memberships">{{member.Name}}
</ion-item>
</ion-list>
Getting my data [Object object] on my ion-item. What's the problem? I don't understand.
Try this:
ionViewDidEnter() {
this.authservice.getmembers().then( data => {
this.memberships = data;
} );
}

Change detection running infinitely when function is used with ngIf

I am working on an Ionic 2 project. The template has a ngIf to check if its the right user.
show.ts
constructor( public book: Bookemon ){}
rightUser(){
console.log('right user');
return this.book.rightUser(this.hunt.user.id);
}
bookemon.ts (bookemon and auth are services )
rightUser(id: number){
return this.auth.user.id === id;
}
show.html
<ion-content fullscreen="true">
<div id="image-modal" >
<img [src]="imageSource(hunt.picture_url)" (click)="dismissModal()" >
<button ion-fab mini *ngIf = " !hunt.picture_url " (click)="showEditHuntModal()" color="ionic">
<ion-icon name="add" ></ion-icon>
</button>
<button color="danger" class="new-claim" ion-button round icon-left *ngIf = "rightUser() && hunt.claims.length " (click)="openClaimModal(hunt)">
<ion-icon name="trophy"></ion-icon>
New Claim
</button>
</div>
<div class="hunt-content">
<button small clear ion-button icon-only class="options" *ngIf="rightUser()" (click)="presentAction()">
<ion-icon name="md-more"></ion-icon>
</button>
<hunt [hunt]="hunt" [huntedUser]="huntedUser" ></hunt>
</div>
<ion-fab *ngIf="hunt.dfu !== undefined" bottom (click)="dismissModal('rejected')" class="close-fab">
<button ion-fab color="danger" ><ion-icon name="close" ></ion-icon></button>
</ion-fab>
<ion-fab *ngIf="hunt.dfu !== undefined" bottom (click)="dismissModal('accepted')" class="heart-fab">
<button ion-fab color="primary" ><ion-icon name="heart" ></ion-icon></button>
</ion-fab>
</ion-content>
The template displays some content based on *ngIf = "rightUser()"
Everything works fine except , the console is logged with infinitely many right user which comes from rightUser() function. The expected behaviour should be right user logged once in console and no more change detection being run.
Is it a bad practice to use functions in ngIf ? What is triggering change detection infinite times here?
Edit
I tried a function with ngIf in a fresh project and it doesnt run change detection infinite times. I am not sure whats causing it here. Here is my show.ts in case that helps.
export class ShowPage {
hunt: Hunt ;
huntedUser: User;
editHuntPage= EditHuntPage;
claimHuntPage = ClaimHuntPage;
rightUser: Boolean;
constructor(public alert: AlertController , public modal: ModalController, public events: Events
, public toastCtrl: ToastController, private navParams: NavParams , public action: ActionSheetController
, public book: Bookemon , public viewCtrl: ViewController, public nav: NavController) {
console.log(navParams.data);
this.hunt = navParams.data.hunt;
this.rightUser = this.book.rightUser(this.hunt.id);
}
ionViewDidLoad(){
console.log('view');
if(this.hunt.status == "hunted"){
this .book.getHuntedUser(this.hunt).subscribe( (res) => {
this.huntedUser = res.json();
console.log(this.huntedUser);
})
}
}
imageSource(pic: string){
return pic ? pic : CONFIG.noHuntPic ;
}
dismissModal(status?: string){
console.log('dismiss');
this.viewCtrl.dismiss(status);
}
presentAction(){
let actionSheet = this.action.create(
{
title: this.hunt.title ,
buttons: [
{
text: 'Edit',
handler: () => {
let trans = actionSheet.dismiss();
trans.then( () => {
this.showEditHuntModal();
})
return false;
}
},
{
text: 'Delete',
role: 'destructive',
handler: () => {
let trans = actionSheet.dismiss();
trans.then( () => {
this.deleteAlert();
})
return false;
}
},
{
text: 'Cancel',
role: 'cancel',
}
]
})
actionSheet.present();
}
showEditHuntModal(){
let modal = this.modal.create(EditHuntPage,this.hunt);
modal.present();
modal.onDidDismiss( (data) => {
if(data){
this.hunt = data;
}
})
}
deleteAlert(){
let alert = this.alert.create({
title: 'Confirm',
message: 'Do you want to delete this hunt?',
buttons: [{
text: "Delete",
handler: () => { this.deleteHunt() }
}, {
text: "Cancel",
role: 'cancel'
}]
})
alert.present();
}
deleteHunt(){
this.book.deleteHunt(this.hunt.id).subscribe( (res) => {
// this.events.publish("user-hunts:deleted",this.hunt);
this.viewCtrl.dismiss("deleted",this.hunt);
}, (err) => {
this.handleError(err);
})
}
openClaimModal(hunt){
let claimModal = this.modal.create(ShowClaimPage,{hunt: hunt})
claimModal.present();
}
rightUser(){
console.log('right user');
return this.book.rightUser(this.hunt.user.id);
}
handleError(err){
console.log(err);
let error= err.message ? err.message : "Error occured";
let toast = this.toastCtrl.create({ message: error, duration: 2000 , position: 'top'});
toast.present();
}
}
angular uses zones.js to detect if something changes in your app so it will check ngIf each time, you can this something like this :
<button small clear ion-button icon-only class="options" *ngIf="isRightUser" (click)="presentAction()">
<ion-icon name="md-more"></ion-icon>
</button>
//...
<button small clear ion-button icon-only class="options" *ngIf="isRightUser" (click)="presentAction()">
//show.ts
isRightUser:boolean;
constructor( public book: Bookemon ){}
ngOnInit(){
this.isRightUser= rightUser();
}
rightUser(){
return this.book.rightUser(this.hunt.user.id);
}

AngularJS Cannot find a differ supporting object '[object Object]' of type 'object' and Parse Query

So when I try to take my data from my parse query and put it in my array I end up with this error Cannot find a differ supporting object '[object Object]' of type 'object'. My Code for the Html and ts file are below. And my model file is also below. Is there a better way to display this data in the list?
Html:
<ion-header>
<ion-navbar>
<ion-title button-right>Trade</ion-title>
<ion-buttons end>
<button ion-button icon-only (click)="addTrade()">
<ion-icon name="add"></ion-icon>
</button>
</ion-buttons>
</ion-navbar>
</ion-header>
<ion-content>
<ion-searchbar (ionInput)="getItems($event)"></ion-searchbar>
<ion-list [virtualScroll]="items">
<ion-item *virtualItem="let item">
{{ item.offering }} {{item.needs}}
</ion-item>
</ion-list>
</ion-content>
and my ts file
import { Component } from '#angular/core';
import { NavController, NavParams, AlertController } from 'ionic-angular';
import { Items} from "../../trade-model";
var Parse = require('parse');
/*
Generated class for the Trade page.
See http://ionicframework.com/docs/v2/components/#navigation for more info on
Ionic pages and navigation.
*/
#Component({
selector: 'page-trade',
templateUrl: 'trade.html'
})
export class TradePage {
searchQuery: string = ''
items: Items ={
offering: [],
needs: []
}
constructor(public navCtrl: NavController, public navParams: NavParams, public alertCtrl: AlertController) {
Parse.initialize('blankedout','unused', "blankedout");
Parse.serverURL = 'blankedout';
}
ionViewWillEnter(){
this.initializeItems()
}
ionViewWillLeave(){
}
initializeItems() {
var this_ref = this
var Trade = Parse.Object.extend("Trade")
var query = new Parse.Query(Trade);
query.find({
success: function(trades) {
for (var i = 0; i < trades.length; i++) {
this_ref.items.offering = trades[i].get("offer")
this_ref.items.needs = trades[i].get("wants")
}
}
});
}
}
This is the template/interface
export interface Items{
offering: string[];
needs: string[];
}
items is an object. Ionic virtualScroll requires an array to be passed in.
Do you mean to do:
<ion-list [virtualScroll]="items.offering">
<ion-item *virtualItem="let item">
{{ item}}
</ion-item>
</ion-list>

Resources