I am building up an ecommerce web in which i have my order Model class like this
import { User } from './user.model';
export class Order {
constructor(){}
amount: Number = 0;
status: String = "";
date: String = '';
products: [any];
userId: String = '';
user : User;
}
And user model like this
export class User{
name: string = '';
email: string = '';
country: string = '';
city: string = '';
mobileNumber: string = '';
address: string = '';
postalCode : string = '';
nearBy : string = '';
_id : string = '';
}
And i have a cart.service.ts in which i am calculating an order total amount like this
// Total amount
public getTotalAmount(): Observable<number> {
return this.cartItems.pipe(map((product: CartItem[]) => {
return products.reduce((prev, curr: CartItem) => {
return prev + curr.product.price * curr.quantity;
}, 0);
}));
}
Now on my checkout.component.ts i am binding values to order Model class like this
isUserLoggedIn: boolean = false;
orderRawData: any;
order: Order;
placeOrder() {
this.cartService.getTotalAmount().subscribe(total=>{
if (total) {
console.log('amount : ',total);
this.order.amount = total;
this.orderRawData = JSON.parse(localStorage.getItem('cartItem'));
if (this.isUserLoggedIn) {
this.order.userId = this.user._id;
}else{
this.order.user = this.user;
}
this.orderRawData.forEach((item,index)=>{
this.order.products.push({
id : item.product._id,
quantity : item.quantity
})
})
this.order.date = new Date().toLocaleString();
this.order.status = 'Pending';
console.log(this.order);
}
})
}
But it's giving me an error like this
What am i doing wrong?
You have declared order:
order: Order;
Bu it never gets assigned an object, so is undefined when you try to updated one of its properties.
this.order.amount = total;
// <--- undefined here
You somehow need to assign order, for example:
this.orderService.getOrder().subscribe(order => {
this.order = order;
});
Before you can consider updating properties on it.
Your order follows the 'Order' format but it's not initialize.
You can do like this:
1) order: Order = {
amount: 0,
status: null,
....
}
or 2) Update the Order class like:
export class Order {
amount: Number;
status: String;
...
constructor(_amount: Number = 0, _status: String = '', ...) {
this.amount = _amount;
this.status = _status;
....
}
}
In the component:
order: Order = new Order();
Related
first question i post here.
I'm learning js and trying to do some APIs for a college project.
I have the body of the API that passes a JSON object like that:
[
{
"id":1,
"issueDate":"2021/11/29 09:33",
"state": "DELIVERED",
"products": [{"SKUId":12,"description":"a product","price":10.99,"qty":30},
{"SKUId":180,"description":"another product","price":11.99,"qty":20},...],
"supplierId" : 1,
"transportNote":{"deliveryDate":"2021/12/29"},
"skuItems" : [{"SKUId":12,"rfid":"12345678901234567890123456789016"},{"SKUId":12,"rfid":"12345678901234567890123456789017"},...]
},
...
]
I have problems parsing products into an array of product object.
class Product {
constructor(SKUId,description,price, qty,) {
this.id = id;
this.price = price;
this.SKUId = SKUId;
this.qty = qty;
this.description = description;
};
}
module.exports = Product;
And in the end this is the code i use for the parsing:
try {
if (Object.keys(req.body).length === 0) {
return res.status(422).json({ error: `Empty body request` }).end();
}
if (!validate_date(req.body.issueDate) ){
return res.status(422).json({ error:`Issue Date Not Valid ` }).end();
}
if (req.body.products === undefined)
return res.status(422).json({ error: `Products not defined in the call` }).end();
if (req.body.supplierId === undefined)
return res.status(422).json({ error: `SupplierId Not defined` }).end();
let lastID = await db.getLastIdFromTable('RestockOrder');
let trID = incrementID(lastID);
let order = new Restock_order(trID, req.body.issueDate, "ISSUED", req.body.supplierId, undefined);
await db.createRestockOrder(order);
//THIS IS THE LINE OF THE CODE THAT DOESNT WORK
const products = req.body.products.map((x) => new Product(x.SKUId, x.description, x.price, x.qty));
order.addProducts(products);
products.forEach(async (x) => await db.addProductToSKURestockTable(x));
return res.status(200).end();
}
After the command const products = req.body.products.map((x) => new Product(x.SKUId, x.description, x.price, x.qty)); the code launchs an exception (caught in a try- catch block) and i dont know what is the real problem in the parsing.
Thanks to everyone who will help me to fix this
your class product is not valid and constructor should start from id parameter
const products = req.body.products.map((x) => new Product(x.id,x.SKUId,... and so on
class Product {
id: number;
price: number;
qty: number;
description: string;
SKUId:number;
constructor(id:number,SKUId:number,description:string,price:number, qty:number) {
this.id = id;
this.price = price;
this.SKUId = SKUId;
this.qty = qty;
this.description = description;
};
}
When you call to request.body you already are in the array, so no need to add the .products part
I used angular-in-memory-web-api to simulate a data server. when I post a new model to add to database, I get an error because of property id, I think that the genId() method in the service does not works. my model is:
export class WorkHouse implements WorkHouseInterface{
id: number = 0;
title: string = '';
code: string = '';
manager: string = '';
startDate: Date = new Date();
endDate: Date = new Date();
evalUnit: string = '';
}
and, InMemoryDataService is:
#Injectable({
providedIn: 'root'
})
export class InMemoryDataService implements InMemoryDbService{
createDb() {
const workHouses = [{id:1, title: 'work1', code: '523', manager: 'xyz', startDate: new Date(), endDate:new Date(), evalUnit: '1'},
{id:2, title: 'work2', code: '345', manager: 'abc', startDate: new Date(), endDate:new Date(), evalUnit: '2'}];
return {workHouses};
}
genId(workHouses: WorkHouse[]): number {
return workHouses.length > 0 ? Math.max(...workHouses.map(workHouse => workHouse.id)) + 1 : 0;
}
}
so, when I fill the properties of below new model via a form except property id:
this.newWorkHouse = {id:0, title:'',code:'',manager:'',startDate:new Date(''),endDate:new Date(''), evalUnit:''};
and post it via calling addWorkHouse method in WorkHouse.service:
/** POST: add a new workHouse to the server */
addWorkHouse(workHouse: WorkHouse): Observable<WorkHouse> {
return this.http.post<WorkHouse>(this.workHouseUrl, workHouse, this.httpOptions).pipe(
tap((newWorkHouse: WorkHouse) => this.log(`added workHouse w/ id=${newWorkHouse.id}`)),
catchError(this.handleError<WorkHouse>('addWorkHouse'))
);
}
by below code:
this.workHouseService.addWorkHouse(this.newWorkHouse).subscribe(workHouse => {
this.workHouses.push(workHouse)});
but I get an error, and the model is not saved. I think the genId() method does not generate an unique Id for that model. how can I handle this error?
define property id as any to accept null or undefined initial value:
export class WorkHouse implements WorkHouseInterface{
id: any = null;
title: string = '';
code: string = '';
manager: string = '';
startDate: Date = new Date();
endDate: Date = new Date();
evalUnit: string = '';
}
and in the form, initial the newWorkHouse:
this.newWorkHouse = {id:null, title:'',code:'',manager:'',startDate:new Date(''),endDate:new Date(''), evalUnit:''};
or before post the newWorkHose to the server, assign the null or undefined to to its id property:
this.newWorkHouse.id = null;
consider the if (item.id == undefined) statement in post method in the back-end server of in-memory-web-api to call genId(...) method to generate id:
// Create entity
// Can update an existing entity too if post409 is false.
protected post({ collection, collectionName, headers, id, req, resourceUrl, url }: RequestInfo): ResponseOptions {
const item = this.clone(this.getJsonBody(req));
// tslint:disable-next-line:triple-equals
if (item.id == undefined) {
try {
item.id = id || this.genId(collection, collectionName);
} catch (err) {
const emsg: string = err.message || '';
if (/id type is non-numeric/.test(emsg)) {
return this.createErrorResponseOptions(url, STATUS.UNPROCESSABLE_ENTRY, emsg);
} else {
console.error(err);
return this.createErrorResponseOptions(url, STATUS.INTERNAL_SERVER_ERROR,
`Failed to generate new id for '${collectionName}'`);
}
}
}
//......
I really need help, because I don't know why this is happening.
I have an Angular webapp with a Firebase backend. My webapp shows 7 random products from a products collection in Firebase. This 7 random products should be stored so that, the users can see it on different devices.
But if i call my savemethod, something weird is happening. The save method, calls a the method, who generates the 7 random products and i don't know why, because i don't call it expecially.
Heres my code:
export class ProductComponent implements OnInit {
schedulenumbers: ISchedule = { numbers: [] }; //Just an Object with an array of numbers in it
length: number = 0; //lenght is needed to show or hite the list in the template
filteredproducts: IProduct[] = [];
numbers: number[] = []; // the numbers to filter the products
constructor(private productservice: ProductService) {
console.log("constructor wurde aufgerufen");
}
ngOnInit(): void {
this.filteredproducts = [];
console.log("ngOnInit was called")
//get the numbers from the database
this.productservice.getnumbers().subscribe(
numbers => {
this.numbers = numbers.numbers;
}
);
//get all products from the database collection
this.productservice.getallproducts().pipe(
map((products) => {
this.length = products.length;
for (let i = 0; i < 7; i++) {
this.filteredproducts.push(product[this.numbers[i]]);
}
return this.filteredproducts;
})
).subscribe();
}
getRandomproducts(): void {
this.filteredproducts = [];
this.numbers = [];
console.log("getRandomproducts was called");
this.productservice.getallproducts().pipe(
map(products => {
for (let i = 0; i < 7; i++) {
this.numbers[i] = Math.floor(Math.random() * products.length + 1)
if (products[this.numbers[i]] == undefined) {
i -= 1;
}
else {
this.filteredproducts.push(products[this.numbers[i]]);
}
}
console.log(this.numbers);
return this.filteredproducts;
})
).subscribe();
}
saveNumbers(): void {
console.log("savenumbers was called")
console.log(this.numbers);
this.schedulenumbers.numbers = this.numbers;
console.log(this.filteredproducts.length);
this.productservice.updatenumbers(this.schedulenumbers);
}
}
Here is the code for the productservice:
#Injectable({
providedIn: 'root'
})
export class ProductService {
Productcollection: AngularFirestoreCollection<IProduct>;
schedulenumbers: AngularFirestoreDocument<ISchedule>;
numbers: Observable<ISchedule>
Products$: Observable<IProduct[]>;
constructor(private firestore: AngularFirestore, private auth: AngularFireAuth) {
this.auth.currentUser.then(user => {
this.productcollection = this.firestore.collection(`${user.uid}`);
this.schedulenumbers = this.firestore.collection(`${user.uid}`).doc("numbers")
})
}
getallproducts() {
return this.Products$ = this.Productcollection.valueChanges({ idField: 'ProductId' }).pipe(
map(products =>
products.filter(product => product.ProductId != 'numbers')
)
);
}
getnumbers() {
return this.numbers = this.schedulenumbers.valueChanges();
}
updatenumbers(numbers: ISchedule) {
this.schedulenumbers.update(numbers)
}
addrecipe(product: IProduct) {
this.Productcollection.add(product);
}
}
I have attached a picture from the Firefox console that shows that if I press the button for the getRandomproducts method twice and then I press the button for the saveNumbers method, strangely white from the saveNumbers method, the for loop of getrandomproduct number method is called and in the filteredproducts array are not longer only 7, but much more products. But why?
Firefox console
i get flat list from server and i must create a tree that list .
this is my model :
export interface ClaimManagerList {
id: number;
title: string;
parentId: number;
isChilde: boolean;
childs: Childes[];
}
export interface Childes {
id: number;
title: string;
parentId: number;
isChilde: boolean;
}
and in this code i convert flat list to tree list -> childs add to this property childs :
return this.claimsManagerService.getAll(this.searchParam).pipe(
map(data => {
data['records'].forEach(element => {
let model = {} as ClaimManagerList;
if (element.parentId == null) {
model.id = element.id;
model.isChilde = element.isChilde;
model.parentId = element.parentId;
model.title = element.title;
data['records'].forEach(child => {
if (child.parentId == element.id) {
let childe = {} as Childes;
childe.id = child.id;
childe.isChilde = child.isChilde;
childe.parentId = child.parentId;
childe.title = child.title;
model.childs.push(childe)
}
})
this.claims.push(model)
}
})
return this.claims;
})
but it show me error in this line :
model.childs.push(childe)
Cannot read property 'push'
whats the problem ? how can i solve this problem ?
This happening as model.childs is not set to an empty array at the beginning. We can resolve this like:
if(!model.childs) model.childs = [] as Childes[];
model.childs.push(childe) // This line should work fine now.
I'm going to propose some changes to your code to order to improve this. I hope these changes will be useful for you.
return this.claimsManagerService.getAll(this.searchParam).pipe(
map((data: any) => {
data.records.forEach((element: any) => {
let model: ClaimManagerList = {};
if (element.parentId == null) {
model.id = element.id;
model.isChilde = element.isChilde;
model.parentId = element.parentId;
model.title = element.title;
model.childs = [];
data.records.forEach((child: any) => {
if (child.parentId == element.id) {
let childe = {} as Childes;
childe.id = child.id;
childe.isChilde = child.isChilde;
childe.parentId = child.parentId;
childe.title = child.title;
model.childs.push(childe)
}
})
this.claims.push(model)
}
})
return this.claims;
})
So I have this function that is a 'next' button that is supposed to go to the next picture in my array. I have also a 'previous' button that has basically the same code but instead of index adding 1 it subtracts 1. That works fine. But this one won't work. When I hit the next button it automatically goes to the last picture in the array and doesn't see the next image. I thought maybe using the pop method but I am not sure, very new to this
export class PictureModalComponent {
model = {
servNum: '',
servDate: '',
caption: '',
url: '',
id: null,
pictures: []
};
constructor(#Inject(MAT_DIALOG_DATA) public data: any, public dialogRef: MatDialogRef<PictureModalComponent>) {
this.model=data;
}
onPreviousClick() {
this.model.pictures.forEach( (picture: AccessApictures, index: number) => {
if (picture.id === this.model.id)
{
let lastPicture: AccessApictures = this.model.pictures[index-1];
this.model.caption = lastPicture.caption;
this.model.servDate = lastPicture.servDate;
this.model.servNum = lastPicture.aservrecno;
this.model.url = lastPicture.filename;
this.model.id = lastPicture.id;
}
});
}
onNextClick() {
this.model.pictures.forEach( (picture: AccessApictures, index: number) => {
if (picture.id === this.model.id ) {
let nextPicture: AccessApictures = this.model.pictures[index+1];
this.model.caption = nextPicture.caption;
this.model.servDate = nextPicture.servDate;
this.model.servNum = nextPicture.aservrecno;
this.model.url = nextPicture.filename;
this.model.id = nextPicture.id;
}
});
}
}
Creating an index variable should help you by removing your costly loops. It's basically 2 bytes that will save your performance.
index = 0;
model = {
servNum: '',
servDate: '',
caption: '',
url: '',
id: null,
pictures: []
};
constructor(#Inject(MAT_DIALOG_DATA) public data: any, public dialogRef: MatDialogRef<PictureModalComponent>) {
this.model = data;
data.pictures.forEach((pic, index) => {
if (pic.id === data.id) {
this.index = index;
break;
}
}
}
// update index with looping to the last picture if on first
onPreviousClick() {
this.index = this.index === 0 ? this.model.pictures.length - 1 : this.index - 1;
this.updateModel(this.model.pictures[this.index]);
}
// updating index with looping to the first picture if on last
onNextClick() {
this.index = this.index === this.model.pictures.length - 1 ? 0 : this.index + 1;
this.updateModel(this.model.pictures[this.index]);
}
// common logic into a single function
updateModel(pic: AccessApictures) {
this.model.caption = pic.caption;
this.model.servDate = pic.servDate;
this.model.servNum = pic.aservrecno;
this.model.url = pic.filename;
this.model.id = pic.id;
}