Reputation: 93
im a newbie to angular and I'm trying to implement add-to-cart functionality on an angular project. here is the function that adds to cart:
async addToCart(product: Productsobj) {
let cartId = await this.getOrCreateCartId();
let item$ = this.db.object(
"/shopping-carts/" + cartId + "/items/" + product.$key
);
item$
.valueChanges()
.pipe(take(1))
.subscribe((p: any) => {
if (p) item$.update({ quantity: p.quantity + 1 });
else item$.set({ product: product, quantity: 1 });
});
}
here is the error :
core.js:6014 ERROR Error: Reference.set failed: First argument contains an invalid key ($key) in property 'shopping-carts.-Lw2GnUrgt9nMyNKznlW.items.-KrqgOLs07ZkbapP4EGi.product'. Keys must be non-empty strings and can't contain ".", "#", "$", "/", "[", or "]"
i tried changing the function as :
async addToCart(product: Productsobj) {
let cartId = await this.getOrCreateCartId();
let item$ = this.db.object(
"/shopping-carts/" + cartId + "/items/{{product.$key}}"// changed product.$key
);
item$
.valueChanges()
.pipe(take(1))
.subscribe((p: any) => {
if (p) item$.update({ quantity: p.quantity + 1 });
else item$.set({ product: product, quantity: 1 });
});
}
now getting the error as :
core.js:6014 ERROR Error: Uncaught (in promise): Error: Reference.child failed: First argument was an invalid path = "/shopping-carts/-Lw2GnUrgt9nMyNKznlW/items/{{product.$key}}". Paths must be non-empty strings and can't contain ".", "#", "$", "[", or "]"
how do i unwrap the product.$key
properly?
edit: the product argument is an object : console.log(product)
after changing product:product
to productName:product.title
errors are gone , firebase shows:
is there a way to get the whole object in firebase?
Upvotes: 2
Views: 1919
Reputation: 411
I have solved the problem.
Before (With Error)
async addToCart(product: Product) {
let cartId = await this.getOrCreateCartId();
let item$ = this.getItem(cartId, product.$key as string);
item$
.valueChanges()
.pipe(take(1))
.subscribe((item: any) => {
if (item == null)
item$.set({
product: product,
quantity: 1,
});
else item$.update({ quantity: item.quantity + 1 });
});
}
After (Without Error)
async addToCart(product: Product) {
let cartId = await this.getOrCreateCartId();
let item$ = this.getItem(cartId, product.$key as string);
item$
.valueChanges()
.pipe(take(1))
.subscribe((item: any) => {
if (item == null)
item$.set({
product: {
title: product.title,
category: product.category,
price: product.price,
imageUrl: product.imageUrl,
},
quantity: 1,
});
else item$.update({ quantity: item.quantity + 1 });
});
}
just change the Implicit product object to Explicit product object
Upvotes: 0
Reputation: 19
Use the following for the definition of Productsobj interface:
export interface Productsobj
{
key: string;
title: string;
price: number;
category: string;
imageUrl: string;
}
i.e instead of using "$key" use "key". With this the following code works
async addToCart(product: Productsobj) {
const cartId = await this.addOrGetCartId();
const item$ = this.db.object('/shopping-carts/' + cartId + '/items/' + product.key);
item$.valueChanges().pipe(take(1)).subscribe( (item:any) => {
if (item) item$.update({quantity: item.quantity + 1});
else item$.update({product: product, quantity: 1});
});
}
Firebase does not allow you to have keys starting with $ character. If you try to add a new object in database (using firebase console) with key as "$key", following error is flagged: 'Path contains invalid characters'. This is why you are getting error in your Angular app.
Upvotes: 0
Reputation: 11
Use product.payload.val()
to set the product attribute to the product object as follows:
async addToCart(product){
let cartId= await this.getOrCreateCartId();
let item$= this.db.object('/shopping-carts/' + cartId + '/items/' + product.key);
item$.valueChanges().pipe(take(1)).subscribe((item:any) => {
if(item!=null) {
item$.set({product: product.payload.val(), quantity: item.quantity + 1})
}
else item$.set({product: product.payload.val(), quantity: 1});
});
}
Upvotes: 1
Reputation: 80914
Try the following:
let key = product["$key"];
let item$ = this.db.object("/shopping-carts/" + cartId + "/items/" + key);
Use brackets to access the property $key
. Also it's better if you change the property $key
to just key
Upvotes: 1