Torben Van Assche
Torben Van Assche

Reputation: 445

Understanding RxJs pipe and choosing the appropriate operator for it

I wrote this code and was promptly told this way of coding is 'not done' in Angular. They told me to research and use RxJs. I am however struggling to understand what I need for my use case. There are so many different options with the pipe operations that I am getting seriously confused about understanding which I need... So after reading through the documentation I have come to stack overflow to hopefully get a clearer understanding of how the various pipes would work, and what I would need in my case...

I should note that I have only recently started doing Angular, while I understand the concepts of Observables, I am really struggling with setting up pipes, while they seem to be pretty integral in Angular...

First I am getting my data:

getProjects(): Observable<ProjectsData> {
    return this.http.get('../../assets/projects.json') as Observable<ProjectsData>;
  }

and using it in this constructor to assign into my html:

export class ProjectInfoComponent {
  project: IProject;

  constructor(private route: ActivatedRoute, dataReader: DataService) {
    dataReader.getProjects().subscribe(data => {
      route.data.subscribe(result => {
        data.projects.forEach(element => {
          if (element.route === result.id) {
            this.project = element;
          }
        });
      });
    });
  }
}
export interface IProject {
    title: string;
    preview: string;
    header?: string;
    route?: string;
    alternatePreview?: string;
    softwareUsed?: string[];
    text?: string;
    thumbnailSize?: number;
}

export interface ProjectsData {
    projects: IProject[];
}

Link to actual JSON for reference: https://github.com/GrimZero/Portfolio/blob/master/docs/assets/projects.json

Upvotes: 0

Views: 685

Answers (3)

Gaurang Dhorda
Gaurang Dhorda

Reputation: 3387

In your ngOnInit() first get id of routed path.

ngOnInit(){
   const id  = this.route.snapshot.paramMap.get('id');
   this.service.getProjects(id).subscribe(data =>{ this.items = data })
}

then, In your service method is..

getProjects(id){
   return this.http.get('../../assets/projects.json').pipe(
      map(projects => projects.find(project => project.id === id))
   );
}

Upvotes: 1

Blazh
Blazh

Reputation: 53

You can use async pipe for that inside the template and avoid subscription inside the component.

In the component you would have:

private project$: Observable<IProject>;

...
this.project$ = this.dataReader.getProjects().pipe(map(projects => projects.find(project => project.id === id)))

Notice that you need to define id property, in your code you are comparing route object with id. Also consider to move that to ngOnInit instead of putting it into the constructor

In the template:

<div *ngIf="project$ | async as project">
    {{ project }}
</div>

Upvotes: 2

wentjun
wentjun

Reputation: 42576

If you are using RxJS 6, the right way would be to make use of pipeable operators. There are multiple ways of approaching this problem.

One way of doing so would have separate chains to handle the observables from both the service method and route, followed by using combineLatest to obtain the returned values.

const getProjects$ = dataReader.getProjects();
const getRoute$ = getProjects$.pipe(
  switchMap(user => route.data)
);

combineLatest(getProjects$, getRoute$).pipe(
  map(([data, result]) => {
    // handle the rest here
    data.projects.forEach(element => {
      if (element.route === result.id) {
        this.project = element;
      }
    });
  }),
).subscribe();

Upvotes: 1

Related Questions