Reputation: 47
our professor asks us to build a simple e-commerce app with the following components: customers, orders, menu (a navbar) and a cart. We need to display the orders in the front-end depending on the selected customer who is selected from a dropdown menu in the navbar, as the image illustrates:
Once we select a customer its Id is assigned to a variable and then it's used to load the orders based on the customer id (thanks to an endpoint called getOrdersByCustomerId) and then it builds a card for each one. So far so good. The problem is that the function is called only once in the order component with the initial value of 0 and we don't know how to make a dynamic call every time the id changes. Here is the code:
import { Injectable } from '@angular/core';
import { OrdersService } from './orders.service';
@Injectable({
providedIn: 'root'
})
export class MenuService {
constructor() { }
customerId: number = 0;
onCustomerChange(event: Event) {
this.customerId = Number((<HTMLInputElement> event.target).value);
console.log(this.customerId);
}
}
import { HttpClient } from '@angular/common/http';
import { Component, EventEmitter, OnInit, Output } from '@angular/core';
import { CustomerService } from 'src/services/customer.service';
import { MenuService } from 'src/services/menu.service';
@Component({
selector: 'app-menu',
templateUrl: './menu.component.html',
styleUrls: ['./menu.component.css']
})
export class MenuComponent implements OnInit {
constructor(public customerService: CustomerService, public menuService: MenuService) {
this.customers = this.customerService.getCustomers();
console.log(this.customers);
}
ngOnInit(): void {
}
title: string = 'E-commerce';
customers: {
id: number,
name: string,
surname: string
}[] = [];
customer!: {
id: number,
name: string,
surname: string
};
links = [
{name: 'Products', href: '/products', disabled: false},
{name: 'Orders', href: '/orders', disabled: false},
{name: 'Cart', href: '/cart', disabled: true},
];
onCustomerChange(event: Event) {
this.menuService.onCustomerChange(event);
}
}
<nav class="navbar navbar-expand-lg bg-primary">
<div class="container-fluid">
<a class="navbar-brand" routerLink="">{{ title }}</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item" *ngFor="let link of links">
<a class="nav-link" aria-current="page" routerLink="{{ link.href }}" routerLinkActive="active">{{ link.name }}</a>
</li>
</ul>
</div>
<div class="d-flex">
<select (change)="onCustomerChange($event)" class="form-select" aria-label="Customer select">
<option value="0">Select customer</option>
<option *ngFor="let customer of customers" value="{{ customer.id }}" >{{ customer.name }} {{ customer.surname }}</option>
</select>
</div>
</div>
</nav>
<!-- [ngModel]="customer.id"
{{ customer.id }}" (change)="-->
import { HttpClient } from '@angular/common/http';
import { Injectable, OnChanges, OnInit, SimpleChanges } from '@angular/core';
import { CartService } from './cart.service';
import { CustomerService } from './customer.service';
import { MenuService } from './menu.service';
@Injectable({
providedIn: 'root'
})
export class OrdersService implements OnInit {
constructor(
public httpClient: HttpClient,
public cartService: CartService,
public customerService: CustomerService,
public menuService: MenuService) {
this.loadOrdersByClientId(this.menuService.customerId);
}
ngOnInit(): void {
this.loadOrdersByClientId(this.menuService.customerId);
}
private orders: {
id: number,
products: any,
amount: number,
customer: any
}[] = [];
loadOrdersByClientId(id: number) {
this.httpClient.get(`http://localhost:8080/order/by-client-id/${id}`).subscribe((response) => {
//console.log(id);
Object.entries(response).forEach(([key, value]) => {
this.orders.push(value);
})
})
}
getOrders() {
return this.orders;
}
}
import { ChangeDetectorRef, Component, OnInit } from '@angular/core';
import { OrdersService } from 'src/services/orders.service';
@Component({
selector: 'app-orders',
templateUrl: './orders.component.html',
styleUrls: ['./orders.component.css']
})
export class OrdersComponent implements OnInit {
constructor(public ordersService: OrdersService) {}
ngOnInit(): void {
this.orders = this.ordersService.getOrders();
}
orders: {
id: number,
products: any,
amount: number,
customer: any
}[] = [];
}
<div class="card" style="width: 18rem;" *ngFor="let order of orders">
<div class="card-body">
<h5 class="card-title">{{order.id}}</h5>
<h6 class="card-subtitle mb-2 text-muted">{{order.amount}}</h6>
</div>
</div>
Probably there are a tons of bad practices in these scripts since we have been working with Angular for just 1 week, sorry for that. I leave the client component out for brevity since it is not related to the issue (it works, and the IDs are correctly retrieved). Thanks in advance for the help!
Upvotes: 1
Views: 1433
Reputation: 1227
It seems that when the customer is changed, only the customerId is updated and nothing else. One way to trigger a new backend call would be to emit an event when the customerId is updated. Then you can listen for it in the order component and trigger a new backend call.
In your menuservice:
import { Injectable, EventEmitter } from '@angular/core';
import { OrdersService } from './orders.service';
@Injectable({
providedIn: 'root'
})
export class MenuService {
public customerIdUpdate = new EventEmitter();
constructor() { }
customerId: number = 0;
onCustomerChange(event: Event) {
this.customerId = Number((<HTMLInputElement> event.target).value);
this.customerIdUpdate.emit();
console.log(this.customerId);
}
}
And then you can subscribe to the event in your order component as follows:
import { ChangeDetectorRef, Component, OnInit } from '@angular/core';
import { OrdersService } from 'src/services/orders.service';
import { MenuService } from './menu.service';
@Component({
selector: 'app-orders',
templateUrl: './orders.component.html',
styleUrls: ['./orders.component.css']
})
export class OrdersComponent implements OnInit {
constructor(public ordersService: OrdersService, public menuService: MenuService) {}
ngOnInit(): void {
this.orders = this.ordersService.getOrders();
this.menuService.customerIdUpdate.subscribe(()=>{
this.orders = this.ordersService.getOrders();
})
}
orders: {
id: number,
products: any,
amount: number,
customer: any
}[] = [];
}
Upvotes: 1