0

I made an Angular Service that keeps a list of items that other components can add items to and can retrieve. For some reason nothing gets added to the list. It does only within the add() function of my service but the variable doesn't get changed outside of it.. For example, at the end of the add() function, the console returns the item that was added. But when I check the list again from the getItems() function list is empty. Why would list doesn't get updated outside of the function after push?

    export class BasketService {
      private list: Item[] = [];
      constructor() {}

      add(product: Product, units: number): void {
        let item: Item = new Item();
        item.product = product;
        item.units = units;
        this.list.push(item);
        console.log(this.list[(this.list.length - 1)]);
        // Log shows item object
      }
      getItems(): Observable<Item[]> {
        console.log(this.list);
        // Log shows empty array
        return of(this.list);
      }
    }

EDIT

getItems() does have a subscriber however the issue doesn't seem to come from there since it receives an empty array of Item, the same empty list that is printed by the console in getItems (in the basketService).

export class BasketComponent implements OnInit {
  items: Item[];

  constructor(private basketService: BasketService) {}

  ngOnInit() {
    this.getItems();
    console.log(this.items.length);
  }
  getItems(): void {
    this.basketService.getItems()
      .subscribe(items => {
        this.items = items; });
  }

4
  • 1
    How do you call getItems ? Commented Mar 16, 2019 at 19:01
  • Seems like getItems() is only called once on subscription, and will not be updated further. Suggest you to use a rxjs Subject (or possibly a BehaviorSubject to always provide last value to subscribers), call next method every time the list is updated to inform subscribers. Them, your getItems method may return your Subject as a Observable (to avoid values to be emitted from outside your service). Commented Mar 16, 2019 at 19:12
  • Are you subscribing to the returned observable ? Commented Mar 16, 2019 at 19:17
  • Yes I'm using a subscriber, it does receive the list but it's empty (initialized but empty). Commented Mar 16, 2019 at 23:21

2 Answers 2

1

Your getItems() method returns an Observable holding your list of items. You need to subscribe to that Observable to get the items.

Also, you could use a BehaviorSubject to push the list in the Observable every time the list is modified.

That way, your service consumers will get notified through the observable when there is an item added.

@Injectable()
export class BasketService {
  private list: Item[] = [];
  private subject = new BehaviorSubject<Item[]>([]);
  private list$ = this.subject.asObservable();

  add(product: Product, units: number): void {
    let item: Item = new Item();
    item.product = product;
    item.units = units;
    this.list.push(item);
    this.subject.next(this.list); // push the modified list to notify observers
  }
  getItems(): Observable<Item[]> {
    return this.list$;
  }
}

Use it like this:

export class MyComponent implements OnInit {
  constructor(private service: BasketService) { }

  ngOnInit() {
    this.service.getItems().subscribe(items => {
      console.log('list modified', items); // this is executed after each list.push()
    });
  }
}

You could also use scan with a Subject and get rid of the list variable. The list will be created by the scan operator by appending to the previous values:

@Injectable()
export class BasketService {
  private subject = new Subject<Item>();
  private list$ = this.subject.pipe(
    scan((list, item) => [...list, item], [] as Item[]),
  );

  add(product: Product, units: number): void {
    let item: Item = new Item();
    item.product = product;
    item.units = units;
    this.subject.next(item);
  }
  getItems(): Observable<Item[]> {
    return this.list$;
  }
}

Here is a short Stackblitz demo using the scan operator.

Sign up to request clarification or add additional context in comments.

2 Comments

I tried using BehaviorSubject but I'm still getting the same result. The array is staying empty
@OcnLaroche, are you subscribing to the observable ? could you share your subscription code ?
0

Make sure that your service is decorated with @Injectable and provided properly so all your components that use the service have the same instance of a service.

2 Comments

Seems that this is not related to how service is provided, but rather to how Observables and subscriptions are used. Also, the @Injectable decorator is not required, as nothing is being injected into BasketService.
@Injectable is present. The subscriptions appears to be working as well

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.