Dynamically creating input fields... Stuck on what to do on the backend


#1

So basically I am creating a ordering system. A user will select a product and based on the product they select an unknown amount of input fields will be generated (Could be 4 could be 10). The input fields will come from my API in JSON form (so i.e. quantity, width, height, color, etc). So for instance something like this to create the input fields

<ion-list> <ion-item *ngFor="let item of itemList; let i = index;"> <ion-label stacked primary>An item</ion-label> <ion-input type="text" [(ngModel)]="{{ item.name }}"></ion-input> </ion-item> </ion-list>

Now where I’m stuck is how should I handle the back end to submit the values? Right now I’m doing something like this (data is only saved in local storage right now, but it will be stored in a database later). I have no idea how I would dynamically create the newItem object arrray in the saveItem() method below based on the number of inputs that are dynamically created

// Params passed from another page 
prodName:   string    = this.navParams.get('prodName');
prodDesc:   string    = this.navParams.get('prodDesc');
  // Array that will be used to save individual items added to order
  public items = [];

 saveItem() {
  let newItem = {
    prodName: this.prodName,
    prodDesc: this.prodDesc
  };

  this.addItem(newItem);
}

addItem(item) {
  this.dataService.save(this.items);  
  this.navCtrl.pop(SearchProducts);
}

OrderData local storage class

export class OrderData {

constructor(public storage: Storage) {
  console.log('Hello OrderData Provider');
}


getData() {
  return this.storage.get('products');
}

save(data){
  let newData = JSON.stringify(data);
  this.storage.set('products', newData);
}

#2

It’s a bit hard to believe this is actually the code you’re using. Your *ngFor is iterating across itemList, your [(ngModel)] is binding to itemlist, and your controller has items. None of those things are the same. Are they intended to be?


#3

Oops…I wrote that code late I wasn’t fully paying attention. I’m not actually using the code yet that is the next part I’m going to work on tomorrow. I just wanted to get a head start on the back end since I know thats where i’ll get stuck

Edit: updated the first post


#4

I expect it will turn out to be much simpler than you think. You don’t even have to explicitly stringify things. Simply pass your array of items to storage.set() or http.post(). This is by far the most common use case for this sort of operation, so Angular’s Http client (and ionic-storage) know what is expected of them.


#5

What I’m confused about is what do I do here

`saveItem() {
let newItem = {
prodName: this.prodName,
prodDesc: this.prodDesc
};

this.addItem(newItem);`

All products will have prodName and prodDesc and for example one product might also have these plus barcode, itemGroup, value, stock, quantity, and another might not have any of these but would have barcode, isbn, label etc so how do I make the newItems array in this context?


#6

You’re worrying about that in the wrong place. Deal with that when you build up the items array. I don’t know whether you’re doing that all at once or whether there’s some sort of button in the form that adds new items, but just this.items.push({prodName: this.prodName, prodDesc: this.prodDesc, barcode: barcode}) for example, and then your items array is the only thing you need to be saving anywhere.


#7

For example on the products page there is a drop down so they will select from multiple products lets just say product1 and product2. Once they select a product all of the items in the column value for that specific product are fetched from my server. So if they select product1 it’ll return prodName, prodDesc barcode but if they selected product2 it would return prodName, prodDesc, quantity, color etc and each of these would be an input in the form they would have to enter. Once they hit submit these input values will be sent back to my server.

However there are 100s of items and I really dont want to manually create a huge array. I would just like to somehow loop the input values and store them in the array with the key being the name of the input (item.value), and the value being whatever they entered in the input textbox


#8

The fundamental thing that is unclear (because of the *ngFor) is this:

Is this page intended to allow users to order multiple different products in a single page, or is it only intended to add one product to an ongoing order that is managed somewhere else?

I would highly recommend going for the former approach rather than the latter, both for ease of coding and for UX.


#9

Yes its the latter. After they submit the first form the y can select another product or checkout


#10

I would suggest changing things so that each product selector is an embedded component, and there is only one order page, that tracks the entire order.


#11

What do you mean by that? Could you give an example?


#12

Can you describe how the user is expected to decide which products are to be included in an order?


#13

Screen 1: User searches and selects a product by searching via an autocomplete.

Screen 2: Users enters details for the product they selected (i.e. quantity, color)
After clicking add to order they are returned to the search screen, where they can search for more products (and keep repeating steps 1 or 2) or click on submit order at which point they are taken to a checkout screen


#14

OK, then I guess you would have a ProductChoosingPage, an OrderAddingPage and a CartPage.

interface OrderItem {
  prodName: string;
  prodDesc: string;
  barcode?: string;
  color?: string;
  quantity?: string;
  // etc for all other possibilities
}

ProductDirectory {
  constructor(private _http: Http) {}
  orderItemFromProductName(pn: string): Observable<OrderItem> {
    return this._http.get(url).map(rsp => rsp.json());
  }
}

ProductChoosingPage {
  onProductChosen(oi: OrderItem): void {
    this._nav.push(OrderAddingPage, {item: oi});
  }
}

OrderAddingPage {
  item: OrderItem;
  constructor(np: NavParams, private _cart: CartService, private _nav: NavController) { 
    this.item = np.get('item') ;
  }
  has(propname: string): boolean { 
    return this.item.hasOwnProperty(propname); 
  }
  addToCart(): void {
    this._cart.add(item);
    this._nav.pop();
  }
}

<ion-item><ion-label>{{item.prodName}}</ion-label></ion-item>
<ion-item *ngIf="has('barcode')"><barcode item-content [code]="item.barcode"></barcode></ion-item>
<ion-item *ngIf="has('color')"><ion-input [(ngModel)]="item.color" placeholder="color"></ion-input></ion-item>
<button (click)="onProductChosen()">add item</button>

CartService {
  items = [] as OrderItem[];
  addItem(oi: OrderItem): void { this.items.push(oi); }
}

CartPage {
  constructor(public cart: CartService) {}
}

<ion-card *ngFor="item of cart.items">
<!-- similar markup to OrderAddingPage but probably read-only -->
</ion-card>