Typical Use Cases Observed Objects In Components In Angular 4

How to Use of Observable Objects in Angular 4 Main Logo

Typical Use Cases Observed Objects In Components And Services In Angular 4

We are presenting to your attention the typical options of using Observable objects in components and services of Angular 4.

How to Use of Observable Objects in Angular 4 Photo 1

Task: When you open the example.com/#/users/42 page, by userId retrieve the user’s data.

Solution: When initializing the UserDetailsComponent components, we subscribe to the router parameters. That is if userId will change – the bumper will trigger our subscription. Using the received userId, we from the userService service get Observable with user data.

// UserDetailsComponent

ngOnInit() {
  this.route.params
    .pluck('userId') // get userId from the parameters
    .switchMap(userId => this.userService.getData(userId))
    .subscribe(user => this.user = user);
}

How to Use of Observable Objects in Angular 4 Photo 2

Task: When you open example.com/#/users/42?regionId=13, you need to execute the load (userId, region) function. Where userId we get from the router, and regionId – from the request parameters.

Solution: We have two event sources, so use the Observable.combineLatest function, which will fire when each source generates an event.

ngOnInit() {
  Observable.combineLatest(this.route.params, this.route.queryParams)
    .subscribe(([params, queryParams]) => { // the received array is structured
      const userId = params['userId'];
      const regionId = queryParams['regionId'];
      this.load(userId, regionId);
    });
}

Note that the created subscriptions to the router, when the object is destroyed, are deleted, followed by an angular, so you do not need to unsubscribe from the router parameters:

The Router manages the observables it provides and localizes the subscriptions. The subscriptions are cleaned up, when the component is closed, protecting against memory leaks, so we do not need to unsubscribe from the route params Observable. Mark Rajcok

How to Use of Observable Objects in Angular 4 Photo 3

Task: Show the download icon after you start saving data and hide it when data is saved or an error occurs.

Solution: For loading the loader, the loading variable responds, after clicking on the button, set it to true. And to set it to false, we use Observable.finally the functions that are executed after the subscription is completed or if an error occurred.

save() {
  this.loading = true;
  this.userService.save(params)
    .finally(() => this.loading = false)
    .subscribe(user => {
      // Successfully saved
    }, error => {
      // Error saving
    });
}

How to Use of Observable Objects in Angular 4 Photo 4

Task: Create a variable lang$ in configService, to which other components will subscribe and respond when the language changes.

Solution: We use the BehaviorSubject class to create the variable lang$;

The Differences a BehaviorSubject from Subject:

  1. BehaviorSubject must be initialized with the initial value;
  2. The subscription returns the last value of Subject;
  3. You can get the last value directly via the getValue() function.

Create a variable lang$ and immediately initialize it. Also, add the setLang function to set the language.

// configService
lang$: BehaviorSubject<Language> = new BehaviorSubject<Language>(DEFAULT_LANG);
setLang(lang: Language) {
  this.lang$.next(this.currentLang); // here we put it
}

Signing up for changing the language in the component. The variable lang$ is a “hot” Observable object, that is, a subscription requires a deletion when the object is destroyed.

private subscriptions: Subscription[] = [];
ngOnInit() {
  const langSub = this.configService.lang$
    .subscribe(() => {
      // ...
    });
  this.subscriptions.push(langSub);
}
ngOnDestroy() {
  this.subscriptions
    .forEach(s => s.unsubscribe());
}

How to Use of Observable Objects in Angular 4 Photo 5

You can unsubscribe and more elegant option, especially if the component has more than two subscriptions:

private ngUnsubscribe: Subject<void> = new Subject<void>();

ngOnInit() {
  this.configService.lang$
    .takeUntil(this.ngUnsubscribe) // unsubscribe by condition
    .subscribe(() => {
      // ...
    });
}

ngOnDestroy() {
  this.ngUnsubscribe.next();
  this.ngUnsubscribe.complete();
}

That is, not to lose memory on hot subscriptions, the component will work until the value of ngUnsubscribe does not change. And it will change when ngOnDestroy is called. The pros of this option are that in each of the subscriptions it is enough to add just one line so that the answer works on time.

How to Use of Observable Objects in Angular 4 Photo 6

Task: Show page suggestions when entering data on a form

Solution: Let’s subscribe to the change of the form data, take only the changing data of the intuitive, put a small delay so that events are not too much and send a request to Wikipedia. The result is output to the console. An interesting point is that switchMap will cancel the previous query if new data has arrived. This is very useful for avoiding non-fire effects from slow queries, if, for example, the penultimate query was 2 seconds long, and after 0.2 seconds, the result of the last request will be displayed in the console.

ngOnInit() {
  this.form.valueChanges
    .takeUntil(this.ngUnsubscribe)      // unsubscribe after destruction
    .map(form => form['search-input'])  // the data of the input
    .distinctUntilChanged()             // select the changed data
    .debounceTime(300)                  // do not react immediately
    .switchMap(this.wikipediaSearch)    // switch Observable to query in Wiki
    .subscribe(data => console.log(data));
}

wikipediaSearch = (text: string) => {
  return Observable
    .ajax('https://api.github.com/search/repositories?q=' + text)
    .map(e => e.response);
}

 

How to Use of Observable Objects in Angular 4 Photo 7

Task: You need to cache Observable query

Solution: Use the bindings publishReplay and refCount. The first function caches one function value for 2 seconds, and the second will count the created subscriptions. That is, Observable will end when all subscriptions are executed. Here you can read more.

// tagService

private tagsCache$ = this.getTags()
  .publishReplay(1, 2000) // caches one value for 2 seconds
  .refCount()             // consider references
  .take(1);               // take 1 value

getCachedTags() {
  return tagsCache$;
}

How to Use of Observable Objects in Angular 4 Photo 8

Task: Critical situation on the server! Backend team reported that for correct product updates it is necessary to perform strictly sequentially:

  1. Updating product data (title and description);
  2. Updating the product tag list;
  3. Updating the list of product categories;

Solution: We have 3 Observable received from the productService. We use concatMap:

const updateProduct$ = this.productService.update(product);
const updateTags$ = this.productService.updateTags(productId, tagList);
const updateCategories$ = this.productService.updateCategories(productId, categoryList);

Observable
  .from([updateProduct$, updateTags$, updateCategories$])
  .concatMap(a => a)  // update sequentially
  .toArray()          // Return an array from the sequence
  .subscribe(res => console.log(res)); // res contains an array of query results

Try that solve this task:

If you have a desire to practice a little, solve the previous problem, but to create a product. That is, first create a product, then update the tags, and only then – categories.