loading...

Two Ways of Using Angular Services With the HttpClient

juliandierkes profile image Julian Dierkes Updated on ・3 min read

Angular Level:

level


The Old Fashioned Way: The 'Pull' Approach

When starting to build an Angular app you most likely come to the point where you need some kind of HTTP communication.
I guess every intermediate Angular user has used the http client before.
Most likely it was wrapped in an Angular service.
E.g. a service for a shopping list app could look like this:

@Injectable({
  providedIn: 'root'
})
export class ShoppingListPullService {

  ITEMS_URL = 'assets/items.json';

  constructor(private httpClient: HttpClient) {
  }

  getItems(): Observable<ShoppingItem[]> {
    return this.httpClient.get<ShoppingItem[]>(this.ITEMS_URL);
  }
}

A component then gets the shopping items via a simple method call, stores them and can display them like this:

@Component({
  selector: 'app-pull',
  template: `
      <div *ngFor="let user of items">
          - {{user.quantity}} {{user.name}}
      </div>
  `
})
export class PullComponent implements OnInit {

  items: ShoppingItem[];

  constructor(private readonly shoppingListService: ShoppingListPullService) {
  }

  ngOnInit(): void {
    this.shoppingListService.getItems()
      .subscribe(items => this.items = items);
  }
}

Note that we don't need to unsubscribe here, as the angular HttpClient handles this for us.
If we had another kind of Observable here, we would also need to unsubscribe.

Let's call this approach the "Pull Approach", because it pulls the data from the service and the component is responsible for holding the state (in this case the array of shopping items).
After any possible change of the items a refetch must be done including the corresponding subscribe block.

This approach is nice and simple, but may not be suitable if multiple components use the service and all of them should share one consistent state.
E.g. imagine you have a component for listing the items and one component for adding new items.
Both components need control of the list.

Observable Data Service: The 'Push' Approach

Here an "Observable Data Service" or "Service With a Subject" is much more convenient.
It may look like this:

@Injectable({
  providedIn: 'root'
})
export class ShoppingListPushService {

  ITEMS_URL = '/assets/items.json';

  private readonly items$: BehaviorSubject<ShoppingItem[]> = new BehaviorSubject<ShoppingItem[]>([]);

  constructor(private httpClient: HttpClient) {
  }

  fetchList() {
    this.httpClient.get<ShoppingItem[]>(this.ITEMS_URL)
      .subscribe(receivedItems => this.items$.next(receivedItems));
  }

  get items(): Observable<ShoppingItem[]> {
    return this.items$.asObservable();
  }
}

Let's have a look on how this works:

The fetchList method executes an HTTP request.
After it returned the items successfully they are published to the BehaviourSubject items$, which means that anyone subscribed to this subject will get that new array of items.
This Subject is made public in the form of an Observable by the get method below so nothing can be published from outside of the service.

This kind of service can easily be used with the Angular async pipe.
No need to subscribe to or unsubscribe from anything.

@Component({
  selector: 'app-push',
  template: `
      <div *ngFor="let item of shoppingListService.items | async">
          - {{item.quantity}} {{item.name}}
      </div>
  `
})
export class PushComponent implements OnInit {

  constructor(readonly shoppingListService: ShoppingListPushService) {
  }

  ngOnInit(): void {
    this.shoppingListService.fetchList();
  }
}

Only thing left to do programmatically in the list component is to trigger the data fetch.

So let's again imagine a second component using this service to add items to the shopping list.
After adding an item the component may easily trigger the fetchList() method and cause an update of the item list in the other component.

Pretty easy, huh?

Posted on by:

juliandierkes profile

Julian Dierkes

@juliandierkes

I am a young full stack web developer at bosch connected industry and mainly working with Spring and Angular. In my free time I love making music and enjoy doing all sorts of craftsmanship.

Discussion

markdown guide