1
votes

Goal

I am trying to insert an ion-select value to an array.

Problem

Cannot read property '0' of undefined. I suppose it comes from the file order-menu.html, under the code orderArray[i].quantity

My Code

I have a model file order-array.ts

export interface OrderArray {
  $key?: string,
  menuName: string,
  menuPrice: string,
  quantity: string
}

and order.ts

export interface Order {
  custName: string,
  custPhone: string,
  restoName: string,
  restoPhone: string,
  restoAddress: string,
  message: string,
  orderArray: string
}

Here is my order-menu.ts

import { Component } from '@angular/core';
import { IonicPage, NavController, NavParams, ToastController } from 'ionic-angular';

import { Observable } from 'rxjs';
import { AngularFireAuth } from '@angular/fire/auth';
import { AngularFireDatabase, AngularFireList, AngularFireAction, DatabaseSnapshot } from '@angular/fire/database';

import { ProfileCust } from './../../models/profile-cust';
import { ProfileResto } from './../../models/profile-resto';
import { Menu } from './../../models/menu';
import { Order } from './../../models/order';
import { OrderArray } from './../../models/order-array';

import { OrderCustPage } from '../order-cust/order-cust';

@IonicPage()
@Component({
  selector: 'page-order-menu',
  templateUrl: 'order-menu.html',
})
export class OrderMenuPage {

  today: number = Date.now(); //get current time

  menuRef: AngularFireList<Menu>;
  menuData: Observable<AngularFireAction<DatabaseSnapshot<Menu>>[]>;

  //retrieve customer & resto profile
  profileCust: Observable<ProfileCust>;
  profileResto: Observable<ProfileResto>;

  restoData: {key: string}; //this parameter is passed from HomePage

  menu = {} as Menu;
  order = {} as Order;

  public orderArray : OrderArray[] = [];

  constructor(private afAuth: AngularFireAuth, private afDatabase: AngularFireDatabase,
    private toast: ToastController,
    public navCtrl: NavController, public navParams: NavParams) {
      this.restoData = navParams.get('restoDataPass');
  }

ngOnInit(){
    let dataArray = {
      menuName: 'Name',
      menuPrice: '15000',
      quantity: 1
    }
    this.orderArray.push(dataArray);
    console.log(dataArray);
  }

  ionViewDidLoad() {
    this.afAuth.authState.subscribe(data => {
      if(data && data.email && data.uid){
        this.menuRef = this.afDatabase.list<Menu>(`menu/${this.restoData.key}`);
        this.menuData = this.menuRef.snapshotChanges();

        console.log(this.orderArray);
        // assign the values from profile customer model to order-customer model
        this.profileCust = <Observable<ProfileCust>>this.afDatabase.object(`profile-cust/${data.uid}`).valueChanges();
        this.profileCust.subscribe(res => {
            this.order.custName = res.custName;
            this.order.custPhone = res.custPhone
          //   var d = new Date();
          //  this.order.timestamp = d.getTime()
          }
        );

        // assign the values from profile resto model to order-resto model
        this.profileResto = <Observable<ProfileResto>>this.afDatabase.object(`profile-resto/${this.restoData.key}`).valueChanges();
        this.profileResto.subscribe(res => {
            this.order.restoName = res.restoName;
            this.order.restoPhone = res.restoPhone;
            this.order.restoAddress = res.restoAddress
          }
        );

      }
      else {
      }
    });
  }

  orderMenu(){
    this.afAuth.authState.subscribe(data => {
      if(data && data.email && data.uid){
        // write this order to DB node order-resto
        this.order.orderArray = this.orderArray.toString();
        console.log(this.orderArray);
        this.afDatabase.list(`order-resto/${this.restoData.key}`).push(this.order);

        // write this order to DB node order-cust
        this.afDatabase.list(`order-cust/${data.uid}`).push(this.order);

        this.navCtrl.setRoot(OrderCustPage);
        console.log(this.orderArray);

        this.toast.create({
          message: `Menu sudah dipesan`,
          duration: 3000
        }).present();
      }
      else {
        this.toast.create({
          message: `Mohon mendaftar terlebih dahulu di Menu - Masuk`,
          duration: 3000
        }).present();
      }
    });
  }
}

And order-menu.html

<ion-header>

  <ion-navbar color="primary">
    <ion-title>OrderMenu</ion-title>
  </ion-navbar>

</ion-header>


<ion-content padding>
  <ion-list>
    <ion-item *ngFor="let data of menuData | async ; let i = index ">
      <div item-content>
        <h2>Menu Name: {{data.payload.val().menuName}}</h2>
        <p>Price: {{data.payload.val().menuPrice}}</p>
        <ion-item>
          <ion-label>
            Quantity:
          </ion-label>
          <ion-select [(ngModel)]="orderArray[i].quantity">
            <ion-option value="1">1</ion-option>
            <ion-option value="2">2</ion-option>
          </ion-select>
        </ion-item>
      </div>
    </ion-item>
  </ion-list>

  <ion-item item-content>
    <ion-label floating>Catatan</ion-label>
    <ion-input type="text" [(ngModel)]="order.message"></ion-input>
  </ion-item>
  <button ion-button (click)="orderMenu()">Order</button>

</ion-content>

-- updated 25 October 2018

I have added ngOnInit(){...} (see the code above). And when I print in console.log, I can see that the value inside the array is already assigned. However I still get the same error Cannot read property 'quantity' of undefined

Any help would be appreciated.

2
Are you sure orderArray has elements? - Frank Modica
I have updated my question. Thanks Frank - Brian Ivander T. P.

2 Answers

1
votes

The error is straight forward, you are trying to set a ngModel value which is undefined. As your array is empty and it does not have any elements you are trying to set the index there. Either have your array defined or use a different variable to set the selected value.

After the line

if(data && data.email && data.uid){
    this.menuRef = this.afDatabase.list<Menu>(`menu/${this.restoData.key}`);
    this.menuData = this.menuRef.snapshotChanges();

add this to assign initial value to orderArray[i].quantity:

this.menuData.subscribe(result => {
          for (let i=0; i<result.length; i++){
            let dataArray = {
              menuName: result[i].payload.val().menuName,
              menuPrice: result[i].payload.val().menuPrice,
              quantity: 0
            }
            this.orderArray.push(dataArray);
            console.log(dataArray); //to logthe dataArray
          }
          console.log(result); //to log the result
          console.log(this.orderArray); //to log the orderArray
        });
0
votes

To initialize your orderArray before use it, in ngOnInit method push your elements to the array, like this :

ngOnInit() {
  orderArray.push(obj);
}