Joel Nash
Joel Nash

Reputation: 31

Where did this switchmap's argument come from?

I'm currently following Jogesh Muppala's Angular course on Coursera, and the issue is with the following line of code.

   this.route.params.pipe(switchMap((params: Params) => this.dishService.getDish(+params['id'])))

The rest of the code is below. My understanding so far is that this.route.params is an Observable, and that this.dishService.getDish(+params[id]) will also return an Observable. My issue is understanding how the (params: Params) got there. It's used as the parameters in the arrow function, and that gets used by the getDish function near the end of the statement. However, at the start of the line we could only access params via this.route.params. Is it a different params? The type declaration params: Params makes it look like it's a completely new instance of a Params type. But if so, how could it be used by getDish?

import { Component, OnInit} from '@angular/core';
import {Params, ActivatedRoute} from '@angular/router';
import {Location} from '@angular/common';
import{ Dish} from '../shared/dish';
import { DishService} from '../services/dish.service';
import { switchMap } from 'rxjs/operators';

@Component({
  selector: 'app-dishdetail',
  templateUrl: './dishdetail.component.html',
  styleUrls: ['./dishdetail.component.scss']
})
export class DishdetailComponent implements OnInit {

  dish: Dish;
  dishIds: number[];
  prev: number;
  next: number;


  constructor(private dishService: DishService, private route: ActivatedRoute,
    private location: Location) { 

  }

  ngOnInit() {
    this.dishService.getDishIds().subscribe(dishIds => this.dishIds = dishIds);
    this.route.params.pipe(switchMap((params: Params) => this.dishService.getDish(+params['id'])))
    .subscribe(dish => { this.dish = dish; this.setPrevNext(dish.id); });
  }

  setPrevNext(dishId: number) {
    const index = this.dishIds.indexOf(dishId);
    this.prev = this.dishIds[(this.dishIds.length + index - 1) % this.dishIds.length];
    this.next = this.dishIds[(this.dishIds.length + index + 1) % this.dishIds.length];
  }


  goBack(): void{
      this.location.back();
  }

}

Thank you for reading.

Upvotes: 0

Views: 1047

Answers (2)

electrichead
electrichead

Reputation: 1170

It is a bit like this:

const bmw = {
  type: car,
  attributes: {
    color: 'red',
    year: 2000
  }
}

const attributes = bmw.attributes;

We happen to name two different things with the same name attributes: one is a variable and the other is a property in an object. They are not related except by the unfortunate coincidence of sharing the same name.

In your case, in this.route.params, params is a property in this.route which returns an Observable.

(params: Params) => this.dishService... is an anonymous function which would be the same as writing (function anon(params: Params) { this.dishService... }).bind(this). Here, params is name given to the argument that the function receives.

The above function executes when a new value is emitted on the Observable from this.routes.params. The value that is emitted here is passed into the anonymous function as its argument, which happens to be called params. So it doesn't need a dot notation because it is not referring to the same thing: it's referring to the value that comes out of the Observable.

At the root of this though the anonymous function (the arrow function) is a function that is passed switchMap and this gets executed once for every value that is put on the source Observable (this.route.params). Each time it executes, switchMap passes in the current value in the Observable as that first argument params. SwitchMap expects this function to return to it a new Observable, which is what is returned by this.dishService.getDish.

HTH

Upvotes: 0

Nico
Nico

Reputation: 2021

The (params: Params) is from the router.params and it's the rxjs 6 way of doing observable operator chaining.

In essence what is really going on is .pipe takes a list of functions and each function through the list gets the value of the previous one except if it's preceded by a tap or filter etc...

So

this.route.params.pipe(switchMap((params: Params) => this.dishService.getDish(+params['id'])))

Before was written like

this.route.params.switchMap((params: Params) => this.dishService.getDish(+params['id']))

So it would get the value from route.params pass it into the switchMap operator which would return a new Observable of the the result from the function which you passed into it.

Upvotes: 1

Related Questions