'How to emit a subscribe event in a nested object with Angular?
I have a application in Angular that has a object that i want his acess in every component. This is the object:
export class CartModel {
public items: ItemModel[] = [];
public coupon?: Coupon;
public payment?: PaymentOrderModel;
public discount: number;
public totalQty: number;
public totalFee: number;
public totalValue: number;
}
This object have a nested object called payment that can be null, this is the object:
export class PaymentOrderModel {
public type: string = '';
public method: string = '';
public change: number = 0;
public card?: CreditCardModel;
public extra: any;
}
In my application i have a service called CartService that have this CartModel object.
This is the service line:
private currentCartSubject: BehaviorSubject<CartModel> = new BehaviorSubject<CartModel>(new CartModel());
constructor(
private storageService: StorageService,
private snackBarService: SnackBarService,
private authService: AuthService,
private companyService: CompanyService,
private http: HttpClient
) {}
getCurrentCart() {
return this.currentCartSubject.asObservable();
}
get cart(): CartModel {
return this.currentCartSubject.value;
}
set cart(cart: CartModel) {
this.currentCartSubject.next(cart);
}
This is the subscribe line:
this.cartService.getCurrentCart().subscribe(
cart => {
console.log("EMITED");
this.cart = cart;
}
);
In another component when a user click the button to choose his payment option i do this:
selectCard(payment: any) {
this.cartService.cart.payment = PaymentOrderModel.setPaymentOnDelivery(payment);
this.facebookService.emitEvent('track', 'AddPaymentInfo');
this.closeModal$.next(true);
}
The problem is this line this.cartService.cart.payment = PaymentOrderModel.setPaymentOnDelivery(payment);, this is the function:
static setPaymentOnDelivery(payment: any): PaymentOrderModel {
return new PaymentOrderModel(
'payment_on_delivery',
payment.method,
0,
null as any,
{ name: payment.name, flag: payment.srcimg, brand: payment.brand }
);
}
This event is not fired and my subscribe don't recieve the object, but if i do this:
this.cartService.cart = new CartModel();
It fire, so the problem is the nested object, in some time ago i have a problem with this in a VueJs application and there they have this function for nested objects:
Vue.set(this.cart, 'payment', { name: payment.name, srcimg: payment.srcimg, brand: payment.brand });
How i can do this in Angular way?
Solution 1:[1]
Regarding following line,
this.cartService.cart.payment = PaymentOrderModel.setPaymentOnDelivery(payment);
You're not calling the setter which is
set cart(cart: CartModel) {
this.currentCartSubject.next(cart);
}
You are firstly calling getter get cart()
, retrieving value and then changing the value of one of its field called payment
.
A BehaviorSubject
will not emit changes if you do not explicitly call next()
method. In your case, you are just modifying the inner variable held by BehaviorSubject
and this change will not be detected.
What I recommend is to clone a CartModel
, override the field, and call setter directly.
this.cartService.cart = {
...this.cartService.cart,
payment: PaymentOrderModel.setPaymentOnDelivery(payment)
}
The three dots operator is called spread operator, you can find more details in MDN
Solution 2:[2]
Your subscriber will receive data when observable will emit data,In your case you are emitting from CartSerice
setter.
this.cartService.cart.payment
- this line calling CartService
getter
this.cartService.cart = new CartModel();
-this line actually calls CartService
setter,thats why subscriber receiving data
So in order to receive data on setting payment,you can do something like bellow
add inside CartService
set payment(payment: PaymentOrderModel) {
this.currentCartSubject.value.payment = payment;
this.currentCartSubject.next(this.currentCartSubject.value);
}
And inside component replace
this.cartService.cart.payment = PaymentOrderModel.setPaymentOnDelivery(payment);
with
this.cartService.payment = PaymentOrderModel.setPaymentOnDelivery(payment);
modified selectCard
selectCard(payment: any) {
this.cartService.payment = PaymentOrderModel.setPaymentOnDelivery(payment);
this.facebookService.emitEvent('track', 'AddPaymentInfo');
this.closeModal$.next(true);
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Tamashii |
Solution 2 |