Home > Back-end >  How to display value from JSON get response in Angular?
How to display value from JSON get response in Angular?

Time:08-26

I'm currently playing around with Angular and a Django Rest API I developed previously. The API has an endpoint which returns the number of currently logged-in users.

I'm able to see the JSON response in my browser console, but I'm not sure how I can display the value of it.

This is what I'm doing at my template:

<div *ngIf="authService.isLoggedIn()" >{{ users_online }}</div>

where the variable users_online only shows [object Promise].

This is how I pull the value from the API at my app.service.ts

import {Injectable} from '@angular/core';
import {HttpClient} from "@angular/common/http";
import {environment} from "../environments/environment";
import {firstValueFrom} from "rxjs";


export interface UsersOnlineCounterResponse {
  users_online: number;
}


const headers = {
  'Authorization': 'Bearer '   localStorage.getItem('access_token'),
}

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

  constructor(private http: HttpClient) { }

  async UsersOnlineCounter() {
    await firstValueFrom(this.http.get<UsersOnlineCounterResponse>(environment.backend   '/api/v1/users/online', {headers})).then(data => {
      return data.users_online;
    }
    );
  }
}

And finally, this is what I do at my app.component.ts

import { Component } from '@angular/core';
import { Title } from '@angular/platform-browser';
import { AppService } from "./app.service";
import { AuthService } from "./auth/auth.service";

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})

export class AppComponent {
  title = 'example.com'
  users_online = this.appService.UsersOnlineCounter();
  constructor(private titleService: Title, public authService: AuthService, public appService: AppService) {
  }
  ngOnInit() {
    this.titleService.setTitle(this.title);
  }
}

CodePudding user response:

Change your service to make use of Observable:

import { Observable } from 'rxjs';
...
UsersOnlineCounter(): Observable<UsersOnlineCounterResponse> {
    return this.http.get<UsersOnlineCounterResponse>(environment.backend   '/api/v1/users/online', {headers}));

And then in your component:

ngOnInit(): void {
   this.appService.UsersOnlineCounter().subscribe((usersOnline) => {
   this.users_online = data.users_online;
}

Angular heavily makes use of the concept of observables. So does RxJs and ngRx

CodePudding user response:

It would be more 'angular' to just use the observables as others answers show, but the problem in your code is that you never return a value:

async UsersOnlineCounter() {
  await firstValueFrom(this.http.get<UsersOnlineCounterResponse>(
    environment.backend   '/api/v1/users/online',
    {headers}))
  .then(data => {
    return data.users_online;
  });

You throw away the value from calling firstValueFrom() without returning it, so your function returns a promise that resolves to undefined. You can add a return in front of the await. Then since your method is async it will return a promise that will resolve to that value. You don't show where you try to use this in your AppComponent, but users_online will be a promise.

The 'angular' way would be to let it be an observable, use the $ naming convention, and us an async pipe to display the data. The service would just return the result from your HttpClient call which would be an observable. I use the rxjs of to emulate that:

import { Injectable } from '@angular/core';
import { of } from 'rxjs';

export interface UsersOnlineCounterResponse {
  users_online: number;
}

@Injectable({
  providedIn: 'root',
})
export class AppService {
  constructor() {}

  GetUsersOnline() {
    // just like an http call that returns 42 for the users online
    return of(<UsersOnlineCounterResponse>{ users_online: 42 });
  }
}

Then in your component you have a variable that just contains that response observable:

import { Component, VERSION } from '@angular/core';
import { AppService, UsersOnlineCounterResponse } from './app.service';
import { Observable } from 'rxjs';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})
export class AppComponent {
  name = 'Angular '   VERSION.major;
  usersOnline$: Observable<UsersOnlineCounterResponse>;

  constructor(public appService: AppService) {
    this.usersOnline$ = appService.GetUsersOnline();
  }
}

And in your template you can use the async pipe and *ngIf to display one element if the observable has a value and another if it hasn't loaded yet:

<p>
  The value returned from GetUsersOnline() is:
  <span *ngIf="usersOnline$ | async as usersOnline; else loading">
    {{ usersOnline.users_online }}
  <span>
  <ng-template #loading>
    <span>fetching user count ...</span>
  </ng-template>
</p>

Sample on stackblitz

  • Related