How to showcase the data retrieved via BehaviorSubject in Angular

I've been working on retrieving data from an API using a service and passing it to components using BehaviorSubject in order to display it on the screen:

Here is the service code snippet:

@Injectable({
    providedIn: 'root',
})
export class UserService {
    userOnChange: BehaviorSubject<User | null> = new BehaviorSubject<User | null>(null);

    constructor(private api: HttpRequestService) {}

    getCurrentUser() {
        this.api.get<User>('/user/me', new HttpParams()).subscribe({
            next: response => {
                this.userOnChange.next(response.body);
            },
        });
    }
}

And here's a snippet of the component code:

@Component({
    selector: 'app-topbar',
    templateUrl: './topbar.component.html',
    styleUrls: ['./topbar.component.scss'],
})
export class TopbarComponent implements OnInit {
    public user: User | null = new User();

    constructor(
        private authService: AuthService,
        private router: Router,
        public userService: UserService,
    ) {
                this.userService.userOnChange.subscribe({
            next: value => {
                if (value != null) {
                    this.user = value as User;
                    console.log(value.Username);
                    console.log(this.user.Username);
                }
            },
        });
    }

    ngOnInit(): void {

    }
}

Lastly, here's a snippet of the template code:

<span *ngIf="this.user && this.user != null"> user: {{ this.user.Username }}</span>

However, I'm facing issues where the displayed value does not change on the template when the subject emits a new user. Additionally, both console.logs within the subscribe block write 'undefined'. Could you please help me identify what I might be doing wrong?

Answer №1

Make sure to wait for the response body. You can use the following code snippet as a guide (not yet verified):

fetchUserDetails() {
    this.api.get<User>('/user/details', new HttpParams()).subscribe({
        next: async result => {
            this.userInformation.next(await result.body);
        },
    });
}

If the above approach doesn't work and your data is in JSON format, consider using .json instead.

fetchUserDetails() {
    this.api.get<User>('/user/details', new HttpParams()).subscribe({
        next: async result => {
            this.userInformation.next(await response.json());
        },
    });
}

Answer №2

No one seems to be making a call to getCurrentUser(), which means that no actual HTTP request is being triggered:

@Component({
    selector: 'app-topbar',
    templateUrl: './topbar.component.html',
    styleUrls: ['./topbar.component.scss'],
})
export class TopbarComponent implements OnInit {
    public user: User | null = new User();

    constructor(
        private authService: AuthService,
        private router: Router,
        public userService: UserService,
    ) {
        this.userService.userOnChange.subscribe({
            next: value => {
                if (value != null) {
                    this.user = value as User;
                    console.log(value.Username);
                    console.log(this.user.Username);
                }
            },
        });
        this.userService.getCurrentUser(); <-- consider adding this line
    }

    ngOnInit(): void {

    }
}

In addition, your current setup requires dealing with subscriptions even after the component has been destroyed. You can simplify it like this:

export class TopbarComponent implements OnInit {
    public user$: BehaviorSubject<User | null>;

    constructor(
        private authService: AuthService,
        private router: Router,
        private userService: UserService,
    ) {
        this.user$ = this.userService.userOnChange;
        this.userService.getCurrentUser();
                
    }

    ngOnInit(): void {

    }
}

and use this template:

<span *ngIf="user$ as user"> user: {{ user.Username }}</span>

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

AngularJS 1: Dynamically updating input values in real-time

Hey everyone, I'm experimenting with Angular and have encountered a roadblock. I am trying to assign values to an input element using ng-repeat for a list of parameters. <input type="text" ng-model="parameters.inParameterName" class="form-control ...

Angular 4: Utilizing reactive forms for dynamic addition and removal of elements in a string array

I am looking for a way to modify a reactive form so that it can add and delete fields to a string array dynamically. Currently, I am using a FormArray but it adds the new items as objects rather than just simple strings in the array. Here is an example of ...

Angular's Mysterious Pipe

When navigating to the indice page, I want to adjust the number formatting in the cours column to display two decimal places. For instance: 11345.654589 should be displayed as 11345.65. https://i.stack.imgur.com/tjvWb.png To achieve this, I have created ...

The type 'undefined' cannot be assigned to a different type within the map() function, resulting in a loss of type information

I am facing an issue in my redux toolkit where an action is trying to set some state. Below is the relevant code snippet: interfaces export interface ProposalTag { id: number; name: string; hex: string; color: string; } export interface ProposalS ...

Dropdown menu not populating with options in AngularJS ngOptions

It's puzzling to me why the dropdown menu is not being populated by ng-options. Despite JSON data being returned from the service and successfully logged in the controller, ng-options seems to be failing at its task. <tr class="info"> <td ...

Retrieve information from an ajax call within an Angular application

I need assistance with 2 requests I have. $.ajax({ type: "POST", url: "http://sandbox.gasvisor.com:9988/uaa/oauth/token", data: "grant_type=client_credentials", headers: { 'Content-Type': 'application/x-www-form-urlencoded&a ...

How do you implement a conditional radio button in Angular 2?

I am facing an issue with two radio buttons functionality. When the first radio button is selected and the user clicks a button, the display should be set to false. On the other hand, when the second radio button is chosen and the button is clicked, ' ...

Leverage the capabilities of one service within another service

I have been working on enhancing the functionality of Http so that when a user encounters a 403 error, their user information is removed and they are redirected to the login page. I have shared an example of AuthHttp below for reference. @Injectable() ...

Issue with Angular reactive forms when assigning values to the form inputs, causing type mismatch

I'm a beginner when it comes to reactive forms. I'm currently working on assigning form values (which are all string inputs) from my reactive form to a variable that is an object of strings. However, I am encountering the following error: "Type ...

Exploring potential arrays within a JSON file using TypeScript

Seeking guidance on a unique approach to handling array looping in TypeScript. Rather than the usual methods, my query pertains to a specific scenario which I will elaborate on. The structure of my JSON data is as follows: { "forename": "Maria", ...

Customize HTML styles using Angular Material

I've noticed that my index.html file has a lot of style elements when using Angular Material, and I'm not sure why. Here's an example in the header element where different classes are used for Angular Material components. Is this setup corr ...

What is the ideal way to name the attribute labeled as 'name'?

When using the ngModel, the name attribute is required. But how do I choose the right name for this attribute? Usually, I just go with one by default. angular <label>First Name</label> <input type="number" name="one" [( ...

Why isn't the customer's name a part of the CFCustomerDetails class?

Currently, I am utilizing the cashfree-pg-sdk-nodejs SDK to integrate Cashfree payment gateway into my application. Upon examining their source code, I noticed that the CFCustomerDetails class does not include the customerName attribute. https://i.stack.i ...

The imported js elements from Bootstrap are failing to function properly despite being successfully included

I want to utilize the collapse feature from Bootstrap in my project. To do so, I have installed jQuery and popper.js: "styles": [ "node_modules/bootstrap/dist/css/bootstrap.min.css", "node_modules/hover.css/css/hover.css", "node_modules/hambur ...

The 'flatMap' property is not found on the 'string[]' data type. This issue is not related to ES2019

A StackBlitz example that I have set up is failing to compile due to the usage of flatMap. The error message reads: Property 'flatMap' does not exist on type 'string[]'. Do you need to change your target library? Try changing the ' ...

The seamless integration of AngularJS and the chosen library is proving to be

When I use a chosen select to load data from a JSON file in an AngularJS application, the data loads successfully with a standard HTML select. However, if I switch to using the chosen select, the data does not load. I understand that the data is fetched af ...

Create a debounce click directive for buttons in a TypeScript file

I'm facing an issue with implementing debounce click on a dynamically added button using TypeScript. I need help with the correct syntax to make it work. private _initActionsFooter(): void { this.actionsFooterService.add([ { ...

The filtering feature for array and model selection in Angular's UI-Select appears to be malfunctioning

Below is a Json structure: $scope.people = [ { name: 'Niraj'}, { name: 'Shivam'}, { name: 'Arun'}, { name: 'Mohit'}] There's also a variable, var array = "Niraj,Shivam";. My goal is to filter out the names fro ...

Trigger a dispatched action within an NGRX selector

I want to ensure that the data in the store is both loaded and matches the router parameters. Since the router serves as the "source of truth," I plan on sending an action to fetch the data if it hasn't been loaded yet. Is it acceptable to perform the ...

Steps for deactivating a button based on the list's size

I am trying to implement a feature where the user can select only one tag. Once the user has added a tag to the list, I want the button to be disabled. My approach was to disable the button if the length of the list is greater than 0, but it doesn't s ...