Home > Back-end >  Getting value from loop inside Angular service file
Getting value from loop inside Angular service file

Time:10-02

Since I am working in Angular, I started to make a simple shopping site. When I add a product to the cart, I see the product name and price without any problems. However, the function I want to show the sum of the prices on the web page does not work. I see total price value in console but I can't return this value. Service.ts file:

import { Injectable } from '@angular/core';
import { basketModel } from './models/basket.model';
import { ProductModel } from './models/product.model';

@Injectable({
  providedIn: 'root'
})
export class DataService {
  baskets: basketModel[]= [
  ];
  
  
  addBasket(product2: ProductModel){
    let cartModel= new basketModel(product2.name,1,product2.price)
    this.baskets.push(cartModel)
    console.log(this.baskets)
    this.totalPrice()
  }
  constructor() { }
  getBasketList():basketModel[]{
  return this.baskets;
  }
  totalPrice(){
    let total=0 // loop is return this value always. If I change the value to 2, I also see the value of 2 on the page.
    for(let i of this.baskets){
      total=total i.price
      console.log(total) // I saw total price value in console. No problem. I want to return this value
      
    }
    return total //not working
  }
  }

I call TotalPrice() like this:

@Component({
  selector: 'app-basket',
  templateUrl: './basket.component.html',
  styleUrls: ['./basket.component.scss'],
})
export class BasketComponent implements OnInit {
  baskets: basketModel[];
  total2: number;

  constructor(dataservice: DataService) {
    this.baskets = dataservice.baskets;
    this.total2=dataservice.totalPrice()
  }

  ngOnInit(): void {
  }
}

Html Page:

<tbody>
        <tr *ngFor="let i of baskets">
            
            <td>{{i.product}}</td>
            <td>{{i.quantity}}</td>
            <td>{{i.price}}</td>
            <td></td>
        </tr>
    </tbody>
    <tfoot>
        <tr>
        
            <th>Total</th>
            <td>{{total2}}</td> <!--  I'm calling the total price value here -->
            <td></td>
            
        </tr>
        
    </tfoot>

What do you think could be the problem? I'll be happy if you can help me.

CodePudding user response:

the issue at hand is that you are performing a one time operation to calculate the price and storing is in total2.

this stores the value returned by the method at the specific point in time it is called. it does NOT pull any updates based on adding new items in the service.

if your goal is for the component to be updated whenever the total changes in the service, then your component needs to be notified when the number baskets changes in the services.

this is where RXJS Subject or BehaviorSubject can be used.

for example, modifying your service as follows to broadcast totals

export class DataService {
  baskets: basketModel[]= [];
  // use a BehaviorSubject if you need the value to be available to any 'late' components
  // if you don't need to worry about 'late' component, a Subject can be used
  total$: BehaviorSubject<number> = new BehaviorSubject<number>(0);
        
  addBasket(product2: ProductModel){
    let cartModel= new basketModel(product2.name,1,product2.price)
    this.baskets.push(cartModel);
    console.log(this.baskets);

    // everytime a new item is added, you need to recalculate the price
    // so pass the new total, so any components using this service can be notified
    this.total$.next( this.totalPrice() );
  }

  constructor() { }

  getBasketList():basketModel[] {
    return this.baskets;
  }

  totalPrice(){
    // loop is return this value always. If I change the value to 2, I also see the value of 2 on the page.
    let total=0 ;

    for(let i of this.baskets){
      total=total i.price
      console.log(total) // I saw total price value in console. No problem. I     want to return this value
      
    }
    return total; //not working
  }
}

with that, you can update your component to use the values from the service as follows

export class BasketComponent implements OnInit {
  baskets: basketModel[];
  total$: BehaviorSubject<number> | undefined

  constructor(dataservice: DataService) {
    this.baskets = dataservice.baskets;
    this.total$ = this.dataservice.total$;
  }

  ngOnInit(): void {
  }
}

finally, update your template to pull the value from the observable, via async

 <td>{{total | async}}</td>

you probably want to review articles about RXJS, observables and state management.

  • Related