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