How can I receive updates when an interface changes in Angular?

I'm attempting to subscribe to my interface and monitor for any changes, but I keep encountering errors.

  1. Fetching data from the API and assigning it to this.candidateProfile :

     export interface CandidateProfile {
     about: string,
     c_id: {},
     certificates_training: [],
     city: string,
     country: string,
     currency: string,
     email: string,
     expectedpayhourly: boolean,
     expectedpayhourlyend: number,
     expectedpayhourlystart: number,
     expectedpaymonthly: {},
     expectedpaymonthlyend: number,
     expectedpaymonthlystart: number,
     experience: [],
     firstname: string,
     hobbies: {},
     jobskills: [],
     langugaes: {},
     lastname: string,
     personalskills: [],
     photo: string,
     remotework: boolean,
     role: string,
     studies: {},
     willingtorelocate: {},
     willingtorelocatecity: {},
     worktype: string
      }
    

Auth.service.ts :

candidateProfile: Observable<CandidateProfile>;

getProfile(id, token) {
const httpOptions = {
  headers: new HttpHeaders({
    'Content-Type': 'application/json',
    'Authorization': `Bearer ${token}`
  })
};

this.http.get(`users/${id}`, httpOptions).subscribe(data => {
  this.candidateProfile = data;
},
  (error) => { console.log(error) },
  () => {
    console.log('received profile', this.candidateProfile);
  })

 }

Component.ts :

this.auth.candidateProfile.subscribe( data => {
console.log(data)
})

Error message :

this.auth.candidateProfile.subscribe is not a function

Answer №1

Adjust your authentication service as shown below

export class AuthService {
    private _candidateProfile$: BehaviorSubject<CandidateProfile> = new BehaviorSubject(null);

    getProfile(id, token): void {
        const httpOptions = {
            headers: new HttpHeaders({
                'Content-Type': 'application/json',
                'Authorization': `Bearer ${token}`
            })
        };

        this.http.get(`users/${id}`, httpOptions).subscribe(data => {
                this._candidateProfile$.next(data);
            },
            (error) => { console.log(error) },
            () => {
                console.log('received profile', data);
            })
    }

    get candidateProfile$(): Observable<CandidateProfile> {
      return this._candidateProfile$.asObservable();
    }
}

You can then use it like this:

this.auth.candidateProfile$.subscribe( data => {
console.log(data)
})

Explanation

The objective is to have an internal observable within the service that will broadcast the current candidate profile.

Anywhere in your application, you are able to subscribe to it and receive the latest fetched profile without triggering the getProfile method again (thus avoiding unnecessary AJAX requests).

To make it easier to consume outside of AuthService, a magic getter has been created to abstract it.

get candidateProfile$(): Observable<CandidateProfile> {
  return this._candidateProfile$.asObservable();
}

This converts the BehaviorSubject into a simple Observable. This ensures that consumers of AuthService cannot directly manipulate the Observable.

The only way to update the CandidateProfile is through this specific block of code:

 this.http.get(`users/${id}`, httpOptions).subscribe(data => {
      this._candidateProfile$.next(data);
 });

I also recommend updating your getProfile function as follows

getProfile(id, token): Observable<CandidateProfile> {
    // [...]
    this.http.get(`users/${id}`, httpOptions).subscribe(data => {
           this._candidateProfile$.next(data);
        },
        // [...]
    );

    return this.candidateProfile$;
}

With this modification, you can interact with your class as demonstrated below:

// Fetch new profile.
this.auth.getProfile(id, token).subscribe();
// Retrieve the last requested profile.
this.auth.candidateProfile$.subscribe();

Answer №2

Subscribing to an observable means subscribing to its value, which is not an observable itself. Instead of storing the value directly, store the observable to maintain its functionality:

this.candidateProfile = data;

By storing the observable in 'this.candidateProfile', you ensure that it retains its subscribe function for future use:

this.candidateProfile = this.http.get(`users/${id}`, httpOptions);

I hope this explanation clarifies things for you. Have a great day!

Answer №3

It's important to consider different approaches when handling observables. Rather than returning the observable in your service file, it is recommended to return it directly in your component.

When it comes to error handling, the choice between handling errors in the service or the component is yours. In the example provided below, I have chosen to handle errors in the component.

In your service file, make sure to include the return statement:

getProfile(id, token) {
  const httpOptions = {
    headers: new HttpHeaders({
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${token}`
    })
  };

  return this.http.get(`users/${id}`, httpOptions);
}

In your component.ts file, subscribe to the observable to retrieve the value:

this.auth.candidateProfile.subscribe( data => {
  console.log(data)
}, error => {
  // handle error
});

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The system encountered an error when attempting to convert the data '19-10-2002' into a date format

I am trying to pass a date parameter in the format (dd-MM-yyyy) and then convert it into the format (yyyy-MM-dd) before sending it via API. Here is my code: convert(date:string){ date //is in the format(dd-MM-yyyy) date = formatDate(date , " ...

Creating Dynamic Templates in Angular 6

We are currently rendering the template dynamically in our application by utilizing AngularJS's $compile to compile HTML on the fly. I am wondering if there is a similar feature in Angular 6 that allows us to manually compile HTML. I have searched for ...

Angular 6 - Outdated Functions

I'm having trouble updating the request options as they are now deprecated. I can't seem to locate the alternative option for this. Can anyone offer some assistance? import { Injectable } from '@angular/core'; import { HttpClient } fr ...

Updating text inputs in Angular can be done more efficiently using Angular Update

I need to make adjustments to an Angular application so that it can run smoothly on older machines. Is there a more efficient method for updating a text input field without using (keyup) to update after each keystroke? I haven't been able to find any ...

Modifying data within nested objects using Typescript

Imagine having an object like this: { b954WYBCC4YbsMM36trawb00xZ32: { activity1: "pending", activity2: "pending" }, ​ pby0CAqQ1hTlagIqBTQf6l2Ti9L2: { activity1: "pending", activity2: "pending" } } with the in ...

Obtaining the host name in server-side rendering (

In the process of developing an app that consists of a client and an API hosted on different domains, the setup resembles the following: [Local] localhost:5000 (client) localhost:5001 (API) [Web] app.domain.com (client) api.domain.com (API) When mak ...

Tips on typing a collection that may hold numerous instances of a particular object

When working with NgRx actions, I need to define the parameter. This parameter is an object that can contain a varying number of specific objects. These objects are already defined in an Interface. export interface CustomDistribution { maxWindowsActive ...

What is the process for modifying the values within a BehaviorSubject<object>?

Assuming we have a BehaviorSubject<object> intelligentObject = new BehaviorSubject<object>( {property1: data1, property2: { subProperty1: info1, subProperty2: info2}, ...} ); Is there a way to modify each value and add new properti ...

Mapping URLs to objects in JavaScript, TypeScript, and Angular4

I have implemented a class called SearchFilter class SearchFilter { constructor(bucket: string, pin: number, qty: number, category: string) { } } When the user performs a search, I populate the filter i ...

Tips on including query parameters in an HTTP GET request

When working with Angular, I encountered a need to append query parameters to the URL. The specific query parameter in question is: filter={"page_name":{"_eq":"login"},"environment":{"_eq":"staging&quo ...

Unable to associate with 'ngIf' as it is not recognized as a valid attribute for 'table'

I've attempted multiple solutions suggested here but none seem to be working. Can someone please assist me? My component.ts is functioning correctly and fetching values without any errors in the console, however, nothing is appearing on the HTML page ...

npm encountered a 401 Unauthorized error while trying to access the latest version of @angular/cli

When attempting to run the npm install -g @angular/cli command in admin mode from the command window, I encountered the error message: npm ERR! 401 Unauthorized: @angular/cli@latest A colleague of mine did not face any issues with this command, and I hav ...

Angular application navigation does not work as expected when the application is served in Express.js

I have an Angular 7 application that is running on an ExpressJS server. This is how the server part of the app is set up: app.get('/', (req, res) => { console.log(`sending...`); res.sendFile(path.join(__dirname, 'index.html') ...

What is the most effective way to structure a React function incorporating nested objects and mapping?

As a newcomer to Typescript, I am facing challenges in properly typing the following code snippet. I have experimented with Interfaces and individually typing properties as well, but it seems like I am only scratching the surface and encountering new typin ...

Discovering the new value of an array object following a push operation in Angular 2

In my Angular 2 .ts file, I have defined an array as follows: this.dropdownValue=[]; I populate this array with values from different functions like this: this.dropdownValue.push({ item_text: this.organizationInfo.records[i]._fields[0].end.properties.n ...

Please ensure the subscription has completed before proceeding with the loop

I am currently working on an Angular application that retrieves data from an API and uses one of its parameters from a looped array. The issue I'm facing is that the data is pushed in a random order due to the continuous looping without waiting for th ...

Converting a string URL to an object type in TypeScript

Is there a way to convert a string URL into an object type in TypeScript? Here is some sample code: type KeyUrl<T> = T extends `/${infer U}` ? U : never; type TUrl<T> = { [k in KeyUrl<T>]: string }; // ---------------------------------- ...

Exploring the contents of JSON data using json-server

In my database file db.json, I have the following data: { "cases":{ "TotalCount":1, "StartingPageNumber":1, "Data":[ { "Id":1, "CaseNumber":& ...

Angular 4 validation triggering the highlighting of control labels

In the process of implementing validation in my Angular 4 application, I have encountered an issue that needs some tweaking. The validation itself is functioning correctly, but I would like to modify the way error messages are displayed. Currently, when ...

Encountering difficulty when determining the total cost in the shopping cart

I am currently working on a basic shopping cart application and I am facing an issue when users add multiple quantities of the same product. The total is not being calculated correctly. Here is my current logic: Data structure for Products, product = { ...