Edit Items in a List Using Modal in Ionic 3 - arrays

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

Related

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 -->

Ion-list not refreshing afer model change

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.

Typescript/Angular - undefined property- how to access variable in array

I learned from debugging that q is undefined in the next() function. How can I get access to "id" in my array in order to push the value from a component(single.Value) to local storage? Thanks so much for any help you can offer!
<ion-navbar color="primary">
<ion-title>Quiz</ion-title>
<ion-buttons start>
<button ion-button icon-left (click)="prev()"><ion-icon name="arrow-back"></ion-icon> Prev</button>
</ion-buttons>
<ion-buttons end>
<button ion-button icon-right (click)="next(q)">Next<ion-icon name="arrow-forward"></ion-icon></button>
</ion-buttons>
</ion-navbar>
</ion-header>
<ion-content padding>
<ion-slides #Quiz>
<ion-slide *ngFor="let q of questions">
{{q.question}}
<range [single]="single"></range>
<progress-bar [progress]="loadProgress"></progress-bar>
</ion-slide>
</ion-slides>
</ion-content>
Typescript file:
export class QuizPage {
public RangeComponent;
public ProgressBar;
single = {
Value: 2
};
questions = [
{id: "programming", question: 'Which programming language do you prefer?'}
constructor(public navCtrl: NavController, public storage: Storage, public rangeComponent: RangeComponent, public progressBar: ProgressBarComponent) {
this.randomizeAnswers(this.questions);
this.setData();
this.getData();
}
randomizeAnswers(questions: any[]): any[] {
for (let i = this.questions.length - 1; i > 0; i--) {
let j = Math.floor(Math.random() * (i + 1));
let temp = this.questions[i];
this.questions[i] = this.questions[j];
this.questions[j] = temp;
}
return this.questions;
}
setData() {
this.storage.set('QuestionData', this.questions);
}
getData() {
this.storage.get('QuestionData').then((data) => {
console.log(data);
});
}
//slides
#ViewChild('Quiz') Quiz: any;
next(q) {
// console.log('single.Value is next');
console.log(this.single.Value);
this.saveToArray(q);
this.single.Value = 2; // Reset value to middle after every question
this.Quiz.slideNext();
this.progressBar.addProgress();
}
saveToArray(q) {
if (q.id == "programming") {
this.storage.set('programming', this.single.Value);
this.storage.get('programming').then((data2) => {
console.log("data logged.");
})
}
q is undefined in the next() function because you are using it outside of your *ngFor.
Instead of passing q into your next function you can use this.Quiz.getActiveIndex() to get the current position of your slider and then get the id from the questions array directly:
this.questions[this.Quiz.getActiveIndex()].id // check if the slide index starts at 0 or 1

ionic 2 get ion-input text to refresh

I have a page with an ion-input in a FormGroup.
When they go to the page, data is loaded from a server. When the data comes in I want the ion-input to be filled in with the data from the server, which the user can then edit and save.
I cannot get the ion-input to show the data. (it remains blank)
Here is the page:
import { Component,ViewChild } from '#angular/core';
import { Validators, FormBuilder, FormGroup } from "#angular/forms";
import { NavController, App, MenuController, NavParams, AlertController,Content } from 'ionic-angular';
import {DomSanitizer,SafeResourceUrl} from '#angular/platform-browser';
import { TabsPage } from '../tabs/tabs';
// Providers
import { ProjectDetailService } from '../../providers/project-detail-service';
#Component({
selector: 'page-form',
templateUrl: 'form.html',
})
export class FormPage {
#ViewChild(Content) content: Content;
newObject: FormGroup;
object: any = {};
objectKey: string = "";
pageTitle: string = "Create New";
videoURL: SafeResourceUrl;
sanitizer: DomSanitizer;
updating: boolean = false;
constructor( public formBuilder: FormBuilder,
public service: ProjectDetailService,
public navParams: NavParams,
public app: App,
public alertCtrl: AlertController,
sanitizer: DomSanitizer ) {
this.sanitizer = sanitizer;
this.newObject = this.formBuilder.group({
name: this.object.name
});
}
setData()
{
this.newObject.value.name = this.object.name;
//none of these work:
//this.content.resize();
//window.location.reload();
//this.app.getRootNav().setRoot(this.app.getRootNav().getActive().component);
}
ionViewDidLoad()
{
this.objectKey = this.navParams.get('projectKey');
console.log("objectkey="+this.objectKey)
this.service.getProject(this.objectKey).subscribe( ( data: any ) => {
this.object = data;
this.setData();
})
}
This is the html:
<ion-content padding>
<form [formGroup]="newObject" (ngSubmit)="save()">
<ion-item>
<ion-label>Project Name</ion-label>
<ion-input type="text" formControlName="name"></ion-input>
</ion-item>
</form>
</ion-content>
I think FormBuilder is not a two way bindier Instead use a simple two way binding like this
<ion-input type="text" [(ngModel)]="name" formControlName="name"></ion-input>
and access as
this.name = 'something';

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