Reputation: 277
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; });
}
Upvotes: 0
Views: 1009
Reputation: 13983
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.
Upvotes: 1
Reputation: 891
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.
Upvotes: 0