Renew Page which has form and fetches items from other page


#1

Hi,

I have a page which is composition of form and lists items dynamically after adding items. My issue is, if i submit or cancel, the form is reset but the list of items remains(I can understand that the html has ngFor)…but I just want the items also be reset … the problem is ngFor does renew every time i access the page, thus the items added remains and lists on the page…

Any suggestion???


#2

Show us the code and your ionic info output please.


#3

Kindly excuse the long code.

HTML


<ion-header>
  <ion-navbar>
    <ion-title>Create Bill </ion-title>
  </ion-navbar>
</ion-header>

<ion-content>
  <ion-segment [(ngModel)]="customer" color="primary">
    <ion-segment-button value="new">
      New Customer
    </ion-segment-button>
    <ion-segment-button value="existing">
      Existing Customer
    </ion-segment-button>
    </ion-segment>
 
<div [ngSwitch]="customer">
  <div *ngSwitchCase="'new'"> 
    <ion-list no-lines>    
      <form [formGroup]="newBillForm" >
        <form [formGroup]="newCustomerForm">
      <ion-item>    
        <p class="photo"><button ion-button (click)="takePhoto()"><ion-icon name="camera" class="pic"></ion-icon>&nbsp; Customer Picture</button></p>   
      </ion-item> 
      <div style="display:flex; flex-direction:column;justify-content:center">    
      <button ion-button (click)="upload()" *ngIf="captureDataUrl">Upload to Firebase!</button>
      </div>
      <img [src]="captureDataUrl"  *ngIf="captureDataUrl"/>   
      
      <ion-input formControlName="fullname" type="text" placeholder="Customer Full Name" name="fullname"></ion-input>
      <ion-input formControlName="mobile" type="number" placeholder="Mobile Number" name="mobile"></ion-input>

      <ion-item>
        <ion-label>Purchase Date</ion-label>
        <ion-datetime formControlName="purchaseDate" [(ngModel)]="purchaseDate.data" displayFormat="MMM DD, YYYY" name="purchaseDate"></ion-datetime>
      </ion-item>
      <ion-item>
        <ion-label>Due Date</ion-label>
        <ion-datetime formControlName="dueDate" [(ngModel)]="dueDate.data" displayFormat="MMM DD, YYYY" name="dueDate"></ion-datetime>
      </ion-item>
      <button ion-button full small type="submit" (click)="saveNewCustomer()" >Save Customer</button> 
        </form>
      <div text-center><button ion-button small full color="secondary" center (click)="addItem()">Add Item</button></div>    
        <ion-label center large full>Items Added</ion-label>            
        
        <ion-item *ngFor="let item of items | async" (click)="showItemOptions(item.$key, item.name, item.quantity, item.units, item.price)" #slidingItem>      
            <ion-col>{{item.itemName}}</ion-col>
            <ion-col>{{item.itemQuantity}} </ion-col>
            <ion-col>{{item.itemBrand}} </ion-col>
            <ion-col>Rs. {{item.itemPrice}}</ion-col>          
        </ion-item>      

    <ion-item class="reg_terms">
       <ion-checkbox secondary name="terms" formControlName="terms"></ion-checkbox>
       <ion-label>Customer accepts the <a href="#">T & C</a></ion-label>
    </ion-item>
    <button ion-button full type="submit" (click)="saveBill()" >Save Bill</button>    
  </form>
  </ion-list>
  </div>
  <div *ngSwitchCase="'existing'" >
    <ion-searchbar (ionInput)="getBills()"></ion-searchbar>      
    <ion-list>
      <ion-item *ngFor="let bill of bills | async" (click)="promptPayment(bill.$key)"
        [class.hide]="bill.paid == true">
        <ion-avatar item-left>
          <img src="assets/img/customers/pic1.jpg">
        </ion-avatar>
        <h2>{{bill.fullname}}</h2>
        <h3>Amount Due: <strong>Rs.{{bill.amount}}</strong></h3>
        <p>Due Date: <strong>{{bill.dueDate | date: 'dd/MM/yyyy'}}</strong></p>                
        <p>Mobile <strong>{{bill.mobile}}</strong></p>                
      </ion-item>
    </ion-list>
  </div>    
</div>
</ion-content>

TS:

import { ActionSheetController } from 'ionic-angular';
import { Component } from '@angular/core';
import { IonicPage, ViewController, NavController, NavParams, AlertController, ModalController, ToastController, Platform, LoadingController, Loading } from 'ionic-angular';
import {AngularFireDatabase, FirebaseListObservable} from 'angularfire2/database';
import { FirebaseProvider } from '../../providers/firebase/firebase';
import firebase from 'firebase';
import { FormGroup, FormBuilder, FormControl, Validators } from '@angular/forms';
import { Camera, CameraOptions, CameraPopoverOptions } from '@ionic-native/camera';
import { File } from '@ionic-native/file';
import { Transfer, TransferObject } from '@ionic-native/transfer';
import { FilePath } from '@ionic-native/file-path';
import * as moment from 'moment';
import { CheckboxValidator } from '../../validators/checkbox';
import { ItemCreatePage } from '../item-create/item-create';

@IonicPage()
@Component({
  selector: 'page-bill-create',
  templateUrl: 'bill-create.html',
  providers: [Camera]
})
export class BillCreatePage {
  
  itemList: FirebaseListObservable<any[]>;
  bills: FirebaseListObservable<any[]>;
  items: FirebaseListObservable<any[]>;
  lastImage: string = null;
  loading: Loading;
  key: any;
  newBillForm: FormGroup; 
  newCustomerForm: FormGroup;
  itemId: string;
  itemName: string;
  itemQuantity: number;
  itemUnit: number;
  itemPrice: number;
  totalAmount: number;
  productPrice: number;  
  imageUrls: any;
  currentCustomer: any;
  photoRef: any;
  images: any;
  purchaseDate = {data: moment ().format(), value: ''};
  dueDate= {data: moment().add(5, 'days').format()};
  Purchase: any;
  customer: any;

  constructor(public navCtrl: NavController, public navParams: NavParams, public alertCtrl: AlertController,
    public angFire: AngularFireDatabase, public toastCtrl: ToastController, public firebaseData: FirebaseProvider,
    public actionSheetCtrl: ActionSheetController, public modalCtrl: ModalController, public formBuilder: FormBuilder,
    private camera: Camera, public viewCtrl: ViewController,
    private transfer: Transfer, private file: File, private filePath: FilePath,
    public platform: Platform, public loadingCtrl: LoadingController
    
  ) {
    this.photoRef=firebase.database().ref('customers/'+this.currentCustomer+'/photos');
    
    this.itemList = angFire.list('/Items');
    this.items = angFire.list('/Items');
    this.bills = angFire.list('/Bills');  
    this.customer = "new"; 
    this.newBillForm = formBuilder.group({
      fullname: ['', Validators.compose([Validators.maxLength(30), Validators.pattern('[a-zA-Z ]*'), Validators.required])],
      mobile:['', Validators.compose([Validators.required, Validators.pattern('^[\+0-9]{10,12}$')])],      
      purchaseDate: [],
      dueDate: [],
      terms: [false,Validators.compose([CheckboxValidator.isChecked, Validators.required])],
      newCustomerForm: []
    });
    this.newCustomerForm = formBuilder.group({
      fullname: ['', Validators.compose([Validators.maxLength(30), Validators.pattern('[a-zA-Z ]*'), Validators.required])],
      mobile:['', Validators.compose([Validators.required, Validators.pattern('^[\+0-9]{10,12}$')])],
      
      purchaseDate: [],
      dueDate: []
    });
  }
  captureDataUrl: string;

  options: CameraOptions = {
    quality: 50,
    destinationType: this.camera.DestinationType.DATA_URL,
    encodingType: this.camera.EncodingType.JPEG,
    mediaType: this.camera.MediaType.PICTURE,
    sourceType: this.camera.PictureSourceType.CAMERA,
    allowEdit: true,
    targetHeight: 100,
    targetWidth: 100,
    saveToPhotoAlbum: false,
    correctOrientation: true
  }

  takePhoto(){
    this.camera.getPicture(this.options).then((imageData) => {
       this.captureDataUrl = 'data:image/jpeg;base64,' + imageData;
    }, (err) => {
       console.log(err);
    });
    
  }


  upload() {
    let storageRef = firebase.storage().ref();

    const filename = Math.floor(Date.now() / 1000);

    // Create a reference to 'images/todays-date.jpg'
    const imageRef = storageRef.child(`images/${filename}.jpg`);

    imageRef.putString(this.captureDataUrl, firebase.storage.StringFormat.DATA_URL).then((snapshot)=> {
      this.showSuccesfulUploadAlert();
    }, err => {});

  }

  showSuccesfulUploadAlert() {
    let alert = this.alertCtrl.create({
      title: 'Uploaded!',
      subTitle: 'Picture is uploaded!',
      buttons: ['OK']
    });
    alert.present();

    // clear the previous photo data in the variable
    this.captureDataUrl = "";
  }

  getPhoto(){
    this.camera.getPicture(this.options).then(function(imageData){
      var image = document.getElementById('customerPhoto');
      this.image = "data:image/jpeg;base64," + imageData;
    }, function(err){
      console.log(err)
    })
    
  }
  
  addItem(){
    this.navCtrl.push(ItemCreatePage)
  }


showOptions(itemId: any, itemName: any, itemQuantity: any, itemUnit: any, itemPrice: any){
  let actionSheet = this.actionSheetCtrl.create({
    title: 'What do you want to do?',
    buttons: [
      {
        text: 'Delete Item',
        role: 'destructive',
        handler: () => {
          this.removeItem(itemId);
        }
      }, {
        text: 'Update Item',
        handler: () => {
          this.updateItem(itemId, itemName, itemQuantity, itemUnit, itemPrice);
        }
      }, {
        text: 'Cancel',
        role: 'cancel',
        handler: () => {
          console.log('Cancel clicked')
        }
      }
    ]
  });
  actionSheet.present();
}

removeItem(itemId: string){
  this.itemList.remove(itemId);
  
}

updateItem(itemId: any, itemName: any, itemQuantity: any, itemUnit: any, itemPrice: any){
  let prompt = this.alertCtrl.create({
    title: 'Item Name',
    message: "Update the name for this item",
    inputs: [
      {
        name: 'name',
        placeholder: 'Item Name',
        value: itemName
      },
      {
        name: 'quantity',
        placeholder: 'Quantity',
        value: itemQuantity
      },
      {
        name:'units',
        placeholder: 'Unit',
        value: itemUnit
      },
      {
        name: 'price',
        placeholder: 'Price',
        value: itemPrice
      }
    ],
    buttons: [
      {
        text: 'Cancel',
        handler: data => {
          console.log('Update canceled')
        }
      },
      {
        text: 'Save',
        handler: data => {
          this.itemList.update(itemId, {
            name: data.name,
            quantity: data.quantity,
            units: data.units,
            price: data.price
          })
        }
      }
    ]
  });
  prompt.present();
}

showItemOptions(itemId: any, itemName: any, itemQuantity: any, itemUnit: any, itemPrice: any){
  let actionSheet = this.actionSheetCtrl.create({
    title: 'What do you want to do?',
    buttons: [
      {
        text: 'Delete Item',
        role: 'destructive',
        handler: () => {
          this.removeItem(itemId);
        }
      }, {
        text: 'Update Item',
        handler: () => {
          this.updateItem(itemId, itemName, itemQuantity, itemUnit, itemPrice);
        }
      }, {
        text: 'Cancel',
        role: 'cancel',
        handler: () => {
          console.log('Cancel clicked')
        }
      }
    ]
  });
  actionSheet.present();
}

getTotal(){
  this.itemPrice += this.itemPrice
  return this.itemPrice;
}

saveNewCustomer(){
 if (!this.newCustomerForm.valid){
   let toast = this.toastCtrl.create({
     message: 'Pls fill the details correctly',
     duration: 3000
   }); toast.present();
 } else {
   this.firebaseData.saveNewCustomer(this.newCustomerForm.value.fullname, this.newCustomerForm.value.mobile, this.newCustomerForm.value.purchaseDate, this.newCustomerForm.value.dueDate).then(() =>{
     let toast = this.toastCtrl.create({
       message: 'Customer Details Saved',
       duration: 3000
     }); toast.present();
   })
 }
}
saveBill(){
  
  if(!this.newBillForm.valid){
    let toast = this.toastCtrl.create({
      message: 'Pls fill the details correctly',
      duration: 3000
    }); toast.present();
  } else {
    this.firebaseData.saveBill(this.newBillForm.value.fullname, this.newBillForm.value.mobile, this.newBillForm.value.purchaseDate, this.newBillForm.value.dueDate, this.newBillForm.value.terms).then(()=>{
      let toast = this.toastCtrl.create({
      message: 'Application submitted successfully!',
      duration: 3000
    }); toast.present();
    
  })
  this.newBillForm.reset();  
}

}



}


ionic info:

global packages:

    @ionic/cli-utils : 1.4.0
    Cordova CLI      : 7.0.1
    Ionic CLI        : 3.4.0

local packages:

    @ionic/app-scripts              : 1.3.7
    @ionic/cli-plugin-cordova       : 1.4.0
    @ionic/cli-plugin-ionic-angular : 1.3.1
    Cordova Platforms               : none
    Ionic Framework                 : ionic-angular 3.4.2

System:

    Node       : v7.3.0
    OS         : Windows 10
    Xcode      : not installed
    ios-deploy : not installed
    ios-sim    : not installed
    npm        : 5.0.2

#4

The way you are accessing items seems to me like it is always going to return Firebase’s /Items. If you want greater control over that, I would suggest losing the AsyncPipe and instead subscribing and updating a controller property that you manage yourself.

Some other things:

  • please get rid of all instances of any
  • it seems weird that you have both AngularFire and direct firebase access
  • date-fns > moment
  • having both formControlName and [(ngModel)] is also weird
  • declaring Camera in a page’s providers is inefficient, because it gets built up / torn down per page
  • do not store Loading in properties - it enables reuse bugs
  • const is less than worthless
  • there is no need for direct DOM access (document.getElementById())
  • never type the word “function” inside of one
  • always prefer let over var
  • I don’t understand how getTotal() is intended to be used, but as written it is incorrectly named. Nothing named getXXX() should modify state.
  • forms cannot nest

#5

Thank you rapropos! I did sanitize as suggested. Few Qs:

  1. Moment does not show correct format if just use ngModel not formControlName for date selection and format. I am trying now with date-fns… Any suggested links/docs shall be great. Although i am going through their docs

  2. I missed to remove getPhoto()

  3. getTotal() … renamed on suggestion to priceTotal() is wherer I want to calculate total of only price value of item. I am not sure how…Any suggestion shall be great ?

  4. Lastly, I have nested Forms and works fine… It saves data to firebase fine… I need to have a Bill Form which has Customer Form and Item Form… Customer Form and Item Form gets saved seperately as well as Bill Form (the master form) saves all data. This I can access seperately on other pages… My issue is the item form lists all items(entered earlier from database) on Bill Create Page… I want to reset the entire page with blank item list…? Any view shall be cool!


#6

Regardless of whether you use moment, having both of those is likely to cause conflict. You should stick to one or the other, and if you’re using reactive forms, that means yes on formControlName and no on ngModel.

What I find odd about that function is that if you call it over and over again it would seem to increment itemPrice to infinity. Is that really what is desired?

Not valid HTML.


#7

Agreed on ngModel with you. priceTotal()… I am looking for looping across different itemPrice and summing it, irresepctive of the number of items. For example, you have 5 items at different prices… I want sum of all item price… Pls suggest a better way…

How do I destroy loop listed items on page leave or back button? Any suggestion


#8

I was afraid this was you.

See this thread and this thread.


#9

Thanks rapropos. Yes, it was me… Any suggestion on destroying the loop


#10

After suggestions, I have made following changes to HTML:


<ion-header>
  <ion-navbar>
    <ion-title>Create Bill </ion-title>
  </ion-navbar>
</ion-header>

<ion-content>
  <ion-segment [(ngModel)]="customer" color="primary">
    <ion-segment-button value="new">
      New Customer
    </ion-segment-button>
    <ion-segment-button value="existing">
      Existing Customer
    </ion-segment-button>
  </ion-segment>
 
  <div [ngSwitch]="customer">
    <div *ngSwitchCase="'new'"> 
    <ion-list>         
      <form [formGroup]="newCustomerForm">
      <ion-item>    
        <p class="photo"><button ion-button (click)="takePhoto()"><ion-icon name="camera" class="pic"></ion-icon>&nbsp; Customer Picture</button></p>   
      </ion-item> 
      <div style="display:flex; flex-direction:column;justify-content:center">    
      <button ion-button (click)="upload()" *ngIf="captureDataUrl">Upload to Firebase!</button>
      </div>
      <img [src]="captureDataUrl"  *ngIf="captureDataUrl"/>   
      
      <ion-item><ion-input formControlName="fullname" type="text" placeholder="Customer Full Name" name="fullname"></ion-input></ion-item>
      <ion-item><ion-input formControlName="mobile" type="text" placeholder="Mobile Number" name="mobile"></ion-input></ion-item>

      <ion-item>
        <ion-label>Purchase Date</ion-label>
        <ion-datetime formControlName="purchaseDate" [(ngModel)]="purchaseDate.data" displayFormat="MMM DD, YYYY" name="purchaseDate"></ion-datetime>
      </ion-item>
      <ion-item>
        <ion-label>Due Date</ion-label>
        <ion-datetime formControlName="dueDate" [(ngModel)]="dueDate.data" displayFormat="MMM DD, YYYY" name="dueDate"></ion-datetime>
      </ion-item>
      <button ion-button full small type="submit" (click)="saveNewCustomer()" >Save Customer</button> 
        </form>     
      
        <ion-label center large full>Items Added</ion-label>            
        <ion-item>Total Bill Value: Rs. {{priceTotal()}}</ion-item>  
        <button ion-button *ngIf="!hide" full small color="secondary" (click)="showItems()">Show Items</button>
        <button ion-button *ngIf="hide" full small color="secondary" (click)="showItems()">Hide Items</button>
        <ion-list *ngIf="hide" type="text" value="">   
        <ion-item *ngFor="let item of items" (click)="showItemOptions(item.$key, item.name, item.quantity, item.units, item.price)" #slidingItem>      
            <ion-col>{{item.itemName}}</ion-col>
            <ion-col>{{item.itemQuantity}} </ion-col>
            <ion-col>{{item.itemBrand}} </ion-col>
            <ion-col>Rs. {{item.itemPrice}}</ion-col>          
        </ion-item>  
        </ion-list> 
        <form [formGroup]="newItemForm">
          <ion-item><ion-input formControlName="itemName" type="text" placeholder="Item Name" name="itemName"></ion-input></ion-item>
          <ion-item><ion-input formControlName="itemQuantity" type="text" placeholder="Item Quantity" name="itemQuantity"></ion-input></ion-item>
          <ion-item>
            <ion-label>Measurement Unit</ion-label>
          <ion-select multiple="false" formControlName="itemUnit" type="text" placeholder="Item Unit" name="itemUnit">
            <ion-option value="grams" selected>Grams</ion-option>
            <ion-option value="kilograms">Kilograms</ion-option>
            <ion-option value="dozens">Dozens</ion-option>
            <ion-option value="inches">Inches</ion-option>
            <ion-option value="foot">Foot</ion-option>
            <ion-option value="centimeters">Centimeters</ion-option>
            <ion-option value="meters">Meters</ion-option>
            <ion-option value="units">Units</ion-option>
            <ion-option value="litres">Litres</ion-option>
            <ion-option value="others">Others</ion-option>
          </ion-select>
          </ion-item>
          <ion-item><ion-input formControlName="itemPrice" type="text" placeholder="Item Price" name="itemPrice"></ion-input></ion-item>
          <ion-item><ion-input formControlName="itemBrand" type="text" placeholder="Item Brand" name="itemBrand"></ion-input></ion-item>
          <button ion-button full small type="submit" (click)="saveNewItem()">Save Item</button> 
        </form>
      </ion-list>
      <button ion-button full type="submit" (click)="saveNewBill()">Save Bill</button>
    </div>
    <div *ngSwitchCase="'existing'" >
      <ion-searchbar (ionInput)="getBills()"></ion-searchbar>      
      <ion-list>
        <ion-item *ngFor="let bill of bills | async" (click)="promptPayment(bill.$key)"
          [class.hide]="bill.paid == true">
          <ion-avatar item-left>
            <img src="assets/img/customers/pic1.jpg">
          </ion-avatar>
          <h2>{{bill.fullname}}</h2>
          <h3>Amount Due: <strong>Rs.{{bill.amount}}</strong></h3>
          <p>Due Date: <strong>{{bill.dueDate | date: 'dd/MM/yyyy'}}</strong></p>                
          <p>Mobile <strong>{{bill.mobile}}</strong></p>                
        </ion-item>
      </ion-list>
    </div>    
  </div>
</ion-content>

rapropos: Pls excuse the ‘moment’ for the time being

Following is the TS:


import { ActionSheetController } from 'ionic-angular';
import { Component } from '@angular/core';
import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';
import { Camera, CameraOptions, CameraPopoverOptions } from '@ionic-native/camera';
import { File } from '@ionic-native/file';
import { FilePath } from '@ionic-native/file-path';
import { Transfer, TransferObject } from '@ionic-native/transfer';
import { AngularFireDatabase, FirebaseListObservable } from 'angularfire2/database';
import firebase from 'firebase';
import {
    AlertController,
    IonicPage,
    ModalController,
    NavController,
    NavParams,
    Platform,
    ToastController,
    ViewController,
} from 'ionic-angular';
import { FirebaseProvider } from '../../providers/firebase/firebase';
import * as moment from 'moment';
import { CheckboxValidator } from '../../validators/checkbox';
import { IonicStorageModule, Storage } from '@ionic/storage';
import 'rxjs/add/operator/map';

@IonicPage()
@Component({
  selector: 'page-bill-create',
  templateUrl: 'bill-create.html',
  
})
export class BillCreatePage {
  
    hide: boolean = true
    items: FirebaseListObservable<any[]>;    
    lastImage: string = null;  
    newCustomerForm: FormGroup;
    newItemForm: FormGroup;
    itemId: string;
    itemName: string;
    itemQuantity: number;
    itemUnit: number;
    itemPrice: number;
    totalAmount: number;
    productPrice: number;  
    currentCustomer: string;
    photoRef: any;
    purchaseDate = {data: moment ().format(), value: ''};
    dueDate= {data: moment().add(5, 'days').format()};
    customer: string;
    fullname: string;
    mobile: number;
    terms: string;

  constructor(public navCtrl: NavController, 
    public navParams: NavParams, 
    public alertCtrl: AlertController,
    public toastCtrl: ToastController, 
    public firebaseData: FirebaseProvider,
    public actionSheetCtrl: ActionSheetController, 
    public modalCtrl: ModalController, 
    public formBuilder: FormBuilder,
    private camera: Camera, 
    public viewCtrl: ViewController,
    private transfer: Transfer, 
    private file: File, 
    private filePath: FilePath,
    public platform: Platform,
    public angFire: AngularFireDatabase,
    public storage: Storage    
    
  ) {
    this.photoRef=firebase.database().ref('customers/'+this.currentCustomer+'/photos');         
    this.customer = "new";     
    this.items = angFire.list('/Items');

    this.newCustomerForm = formBuilder.group({
      fullname: ['', Validators.compose([Validators.maxLength(30), Validators.pattern('[a-zA-Z ]*')])],
      mobile: ['', Validators.compose([Validators.required, Validators.pattern('^[\+0-9]{10,12}$')])],
      purchaseDate: [],
      dueDate: []      
    })
    this.newItemForm = formBuilder.group({
      itemName: ['', Validators.compose([Validators.maxLength(30), Validators.pattern('[a-zA-Z ]*')])],
      itemQuantity: ['', Validators.compose([Validators.required, Validators.minLength(1)])],
      itemUnit: ['', Validators.compose([Validators.required, Validators.minLength(5)])],
      itemPrice: ['', Validators.compose([Validators.required, Validators.minLength(1)])],
      itemBrand: ['', Validators.compose([Validators.required, Validators.minLength(3)])]
    })
  }
  captureDataUrl: string;

  options: CameraOptions = {
    quality: 50,
    destinationType: this.camera.DestinationType.DATA_URL,
    encodingType: this.camera.EncodingType.JPEG,
    mediaType: this.camera.MediaType.PICTURE,
    sourceType: this.camera.PictureSourceType.CAMERA,
    allowEdit: true,
    targetHeight: 100,
    targetWidth: 100,
    saveToPhotoAlbum: false,
    correctOrientation: true
  }

  takePhoto(){
    this.camera.getPicture(this.options).then((imageData) => {
       this.captureDataUrl = 'data:image/jpeg;base64,' + imageData;
    }, (err) => {
       console.log(err);
    });    
  }


  upload() {
    let storageRef = firebase.storage().ref();
    let filename = Math.floor(Date.now() / 1000);
    let imageRef = storageRef.child(`images/${filename}.jpg`);
    imageRef.putString(this.captureDataUrl, firebase.storage.StringFormat.DATA_URL).then((snapshot)=> {
      this.showSuccesfulUploadAlert();
    }, err => {});
  }

  showSuccesfulUploadAlert() {
    let alert = this.alertCtrl.create({
      title: 'Uploaded!',
      subTitle: 'Picture is uploaded!',
      buttons: ['OK']
    });
    alert.present();
    this.captureDataUrl = "";
  }
  

  showOptions(itemId: any, itemName: any, itemQuantity: any, itemUnit: any, itemPrice: any){
    let actionSheet = this.actionSheetCtrl.create({
      title: 'What do you want to do?',
      buttons: [
        {
          text: 'Delete Item',
          role: 'destructive',
          handler: () => {
            this.removeItem(itemId);
          }
        }, {
          text: 'Update Item',
          handler: () => {
            this.updateItem(itemId, itemName, itemQuantity, itemUnit, itemPrice);
          }
        }, {
          text: 'Cancel',
          role: 'cancel',
          handler: () => {
            console.log('Cancel clicked')
          }
        }
      ]
    });
    actionSheet.present();
  }

  removeItem(itemId: string){
    this.items.remove(itemId);    
  }

  updateItem(itemId: any, itemName: any, itemQuantity: any, itemUnit: any, itemPrice: any){
    let prompt = this.alertCtrl.create({
      title: 'Item Name',
      message: "Update the name for this item",
      inputs: [
        {
          name: 'name',
          placeholder: 'Item Name',
          value: itemName
        },
        {
          name: 'quantity',
          placeholder: 'Quantity',
          value: itemQuantity
        },
        {
          name:'units',
          placeholder: 'Unit',
          value: itemUnit
        },
        {
          name: 'price',
          placeholder: 'Price',
          value: itemPrice
        }
      ],
      buttons: [
        {
          text: 'Cancel',
          handler: data => {
            console.log('Update canceled')
          }
        },
        {
          text: 'Save',
          handler: data => {
            this.items.update(itemId, {
              name: data.name,
              quantity: data.quantity,
              units: data.units,
              price: data.price
            })
          }
        }
      ]
    });
    prompt.present();
  }

  showItemOptions(itemId: any, itemName: any, itemQuantity: any, itemUnit: any, itemPrice: any){
    let actionSheet = this.actionSheetCtrl.create({
      title: 'What do you want to do?',
      buttons: [
        {
          text: 'Delete Item',
          role: 'destructive',
          handler: () => {
            this.removeItem(itemId);
          }
        }, {
          text: 'Update Item',
          handler: () => {
            this.updateItem(itemId, itemName, itemQuantity, itemUnit, itemPrice);
          }
        }, {
          text: 'Cancel',
          role: 'cancel',
          handler: () => {
            console.log('Cancel clicked')
          }
        }
      ]
    });
    actionSheet.present();
  }
  saveNew(){
    this.storage.set(`items ${ this.itemId }`, this.itemName);
    console.log(this.items);
  }

  showItems(){
    this.hide = !this.hide    
  }
  
  priceTotal(){
  
  }

  saveNewCustomer(){
  if (!this.newCustomerForm.valid){
    let toast = this.toastCtrl.create({
      message: 'Pls fill the details correctly',
      duration: 3000
    }); toast.present();
  } else {
    this.firebaseData.saveNewCustomer(this.newCustomerForm.value.fullname, this.newCustomerForm.value.mobile, this.newCustomerForm.value.purchaseDate, this.newCustomerForm.value.dueDate).then(() =>{
      let toast = this.toastCtrl.create({
        message: 'Customer Details Saved!',
        duration: 3000
      }); toast.present();
    })
  }
  }

  saveNewItem(){
    if(!this.newItemForm.valid){
      let toast = this.toastCtrl.create({
        message: 'Pls fill the details correctly',
        duration: 3000
      }); toast.present();
    } else {
      this.firebaseData.saveNewItem(this.newItemForm.value.itemName, this.newItemForm.value.itemQuantity, this.newItemForm.value.itemUnit, this.newItemForm.value.itemPrice, this.newItemForm.value.itemBrand).then(()=>{
        let toast = this.toastCtrl.create({
        message: 'Item Saved!',
        duration: 3000
      }); toast.present();
      
    })
    
    }
  }

  saveNewBill(): void{
    if(!this.newCustomerForm.valid && !this.newItemForm.valid){
      let toast = this.toastCtrl.create({
        message: 'Pls fill the details correctly',
        duration: 3000
      }); toast.present();
    } else {
      this.firebaseData.saveNewBill(this.newCustomerForm.value.fullname, this.newCustomerForm.value.mobile, this.newCustomerForm.value.purchaseDate, this.newCustomerForm.value.dueDate, this.newItemForm.value.itemName, this.newItemForm.value.itemQuantity, this.newItemForm.value.itemUnit, this.newItemForm.value.itemPrice, this.newItemForm.value.itemBrand).then(()=>{
        let toast = this.toastCtrl.create({
          message: 'Bill Saved!',
          duration: 3000
        }); toast.present();
      })
    }
  }    

  ionViewWillLeave() {
    console.log('I am leaving');
  }
    

}

Hopefully cleaner? I plan to remove items on ionViewWillLeave through firebase data provider again. Now I see an untracable problem of ngFor:

Runtime Error
Uncaught (in promise): Error: Cannot find a differ supporting object '[object Object]' of type 'object'. NgFor only supports binding to Iterables such as Arrays. Error: Cannot find a differ supporting object '[object Object]' of type 'object'. NgFor only supports binding to Iterables such as Arrays. at NgForOf.ngOnChanges 

Pls share your views


#11

Sorted it… It was pipe async issue. Also the ionViewWillLoad is good enough for removing items too. All works as desired. Any suggestion to improve the code will be appreciated. Thanks!


#12

Just sharing… Nested FormGroups