skip to Main Content

I am trying to get job by job_id via firebase rest api. I am getting this JSON result below. How i can rid of the 0 and get the object?

And Is there better way to get the job via firebase rest api?
This is my code:

{
    "0": {
        "category_id": 0,
        "created_on": "Mar 29, 2024",
        "description": "Dolor justo tempor duo ipsum accusam rebum gubergren erat. Elitr stet dolor vero clita labore gubergren. Kasd sed ipsum elitr clita rebum ut sea diam tempor. Sadipscing nonumy vero labore invidunt dolor sed, eirmod dolore amet aliquyam consetetur lorem, amet elitr clita et sed consetetur dolore accusam.",
        "job_id": "TEL5UAVd5b3Q4jLY2aFfWs4QneMO",
        "job_nature": "Full-time",
        "location": "Gabrovo, Bulgaria",
        "qualifications": [
            "Rebum vero dolores dolores elitr",
            "Elitr stet dolor vero clita labore gubergren",
            "Dolor justo tempor duo ipsum accusam"
        ],
        "salary": "$1500-$1900",
        "title": "Marketing manager",
        "user_id": "qDDuvTWL00N2sNXPhMy2rE0ZB8w2"
    }
}
export class JobDetailComponent implements OnInit {
  job = {} as Job;

  constructor(
    private apiService: ApiService,
    private activeRoute: ActivatedRoute
  ) { }

  ngOnInit(): void {
    this.activeRoute.params.subscribe((data) => {
      const id = data['jobId'];

      this.apiService.getJob(id).subscribe((job) => {
        this.job = job;
        console.log(job)
      });
    });
  }
}
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { environment } from 'src/environments/environment.development';
import { Category } from './types/category';
import { Job } from './types/job';

@Injectable({
  providedIn: 'root'
})
export class ApiService {
  constructor(private http: HttpClient) { }

  getCategories() {
    const { apiUrl } = environment;
    return this.http.get<Category[]>(`${apiUrl}/categories.json`);
  }
  getJobs() {
    const { apiUrl } = environment;
    return this.http.get<Job[]>(`${apiUrl}/jobs.json`);
  }
  getJob(id: string) {
    const { apiUrl } = environment;
    return this.http.get<Job>(`${apiUrl}/jobs.json?orderBy="job_id"&equalTo="${id}"`);
  }
}

2

Answers


  1. In the getJob function, you can use the [map][q] RxJS operator to change the observable value as:

    import { map } from 'rxjs';
    
    getJob(id: string) {
      const { apiUrl } = environment;
      return this.http.get<Record<string, Job>>(`${apiUrl}/jobs.json?orderBy="job_id"&equalTo="${id}"`)
        .pipe(map((resp: Record<string, Job>) => resp["0"] as Job));
    }
    

    If the key is dynamic, you can get the first value from Object.values() function.

    import { map } from 'rxjs';
    
    getJob(id: string) {
      const { apiUrl } = environment;
      return this.http.get<Record<string, Job>>(`${apiUrl}/jobs.json?orderBy="job_id"&equalTo="${id}"`)
        .pipe(map((resp: Record<string, Job>) => Object.values(resp)[0] as Job));
    }
    
    Login or Signup to reply.
  2. To access your data, you simply need to access the 0 (string, not number) key of the returned object, so you could just do:

    this.job = job['0'];
    

    However, since you always want your service to return the Job and not the full object, you should transform your response:

    // service
    getJob(id: string) {
      const url = `${environment.apiUrl}/jobs.json?orderBy="job_id"&equalTo="${id}"`;
    
      return this.http.get<Record<string, Job>>(url).pipe(
        map(response => response['0'])
      );
    }
    
    

    I notice you have nested subscribes, which are not desirable, because without a reference to the subscription object, you have no way to unsubscribe. This means that when you leave your component, the subscription is still active, possibly running your logic after the component has been destroyed.

    There are a few ways to deal with this, but I’ll mention what I find to be the simpliest code. The idea is to define an observable that emits exactly the data your view needs, in this case, the Job. Then, instead of explicitly subscribing in the component’s controller, we can leverage the async pipe in the template which will subscribe to the observable and also unsubscribe when the component is destroyed.

    Here’s an example:

    export class JobDetailComponent {
    
      job$: Observable<Job> = this.activeRoute.params.pipe(
        switchMap(params => this.apiService.getJob(params.id))
      );
    
      constructor(
        private apiService: ApiService,
        private activeRoute: ActivatedRoute
      ) { }
    
    }
    

    You’ll notice in the above code we simply declare the job$ observable. We start with the "active route params observable" and pipe it to the "get job observable".

    If you’re not familiar with switchMap, it simply takes the incoming value and maps it to an observable (in this case the call to apiService.getJob()). The emissions from this "inner observable" are then emitted.

    Now that we have an Observble<Job>, we can simply use the async pipe in the template:

    <div *ngIf="job$ | async as job">
      {{ job.name }} ({{ job.id }})
    </div>
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search