Displaying related objects information from a single object in AngularFire2 can be achieved by following these steps

As a newcomer to Angular and Firebase, I apologize if my question seems basic.

I'm seeking guidance on how to display related object information from one object in angularfire2. Specifically, I want to show the role names assigned to a user.

Here is an example of the structure in the Firebase database:

role: {
  roleKey1: {
    name: Designer
    ...
  },
  roleKey2: {
    name: Manager
    ...
  }
},
user: {
  userKey1: {
     name: Bill,
     roles: {
        roleKey1: true,
        roleKey2: true,
     },
     ...
  },
  userKey2: {
     name: Steve,
     roles: {
        roleKey1: true,
     },
     ...
  },
}

In my controller implementation:

export class UserComponent implements OnInit  {
  public user: Observable<any>;
  public id: string;

  constructor(private af: AngularFire, private activatedRoute: ActivatedRoute) {
  }

  public ngOnInit() {

      const id = this.activatedRoute.params.subscribe(params => {
      if (params['id']) {
        this.id = params['id'];
        console.log(params['id']);
      }
    });

    this.user = this.af.database.object('/user/' + this.id)
    .switchMap((user) => {
      const roleKeys = Object.keys(user.roles);
      return Observable.forkJoin(
        roleKeys.map((roleKey) => this.af.database.object('/role/' + roleKey)
        .first()
        ),
        (...roles) => {
          roleKeys.forEach((roleKey, index) => {
            user.roles[roleKey] = roles[index];
          });
          return user;
        }
      );
    });
  }

In my template design:

<h2>Name: {{ (user | async)?.name }} roles</h2>

<ul *ngFor="let role of user.roles | async">
    <li>{{ role.name }}</li>
</ul>

Current output: Only the user's name is visible, no roles are displayed.

Desired Outcome:

  1. with url:

    • Bill's roles:
      • Manager
      • Designer
  2. with url:

    • Steve's roles:
      • Designer

Your assistance is greatly appreciated!

Answer №1

Below is the proposed solution (untested):

    import { Component, OnInit } from '@angular/core';
    import { ActivatedRoute } from '@angular/router';
    import { Observable } from "rxjs/Observable";
    import { AngularFire } from 'angularfire2';


    interface Role {
        roleKey: string;
        name: string;
    }

    interface User {
      name: string;
      roles: Array<boolean>;
    }

    interface Profile {
        name: string;
        roles: Array<Role>
    }

    export class UserComponent implements OnInit  {
    public user: Observable<any>;
    public id: string;

    constructor(private af: AngularFire, private activatedRoute: ActivatedRoute) {
    }

    ngOnInit() {

        const id = this.activatedRoute.params.subscribe(params => {
        if (params['id']) {
            this.id = params['id'];
            console.log(params['id']);
            this.getProfile(this.id).then(profile =>{
                console.log(profile); // <--- Is it what you want?
                this.user = Observable.of(profile);
            }).catch(error => { console.log(error); }) ;

        }
        });
    }

        getProfile(userKey: string): Promise<Profile> {
            return new Promise(resolve =>{
                var profile: Profile;
                this.af.database.object('/user/' + userKey).subscribe(resUser =>{
                    if(resUser) {
                        var tempUser: User = resUser;
                        var roleKeys = [];

                        profile.name = tempUser.name;

                        roleKeys = tempUser.roles.filter(key =>{
                            return (key == true);
                        });
                        if(roleKeys.length > 0) {
                            var tempRoles = [];
                            var count = roleKeys.length;
                            roleKeys.forEach(roleKey =>{
                                count = count - 1;
                                this.af.database.object('/role' + roleKey).subscribe(resRole =>{
                                    if(resRole) {
                                        tempRoles.push({roleKey: resRole.name});
                                        if(count == 0) {
                                            profile.roles = tempRoles;
                                            resolve(profile);
                                        }
                                    }
                                }, (error) =>{ console.log(error); });
                            });
                        } else {
                            // No roles found. Display name only
                            profile.roles = [];
                            resolve(profile);
                        }

                    }
                }, (error) => { console.log(error); });
            })    
        }

    }

Answer №2

Big thanks to @sugarme for the valuable assistance. I was able to find the solution I needed.

class UserComponent implements OnInit  {

  public user: Observable<any>;
  public id: string;

  constructor(private af: AngularFire, private activatedRoute: ActivatedRoute) {
  }

  public ngOnInit() {

    this.id = this.activatedRoute.params.subscribe(params => {
      if (params['id']) {
        this.id = params['id'];
        console.log(params['id']);
      }
    });

    this.user = this.af.database.object('/user/' + this.id)
    .map(_user => {
      const tempRoleKeys = [];
      const tempRoleObjects = [];
      if (_user.roles) {
        Object.keys(_user.roles)
        .forEach((roleKey, index) => {
          tempRoleKeys.push(roleKey);
          tempRoleObjects.push(this.af.database.object('/role/' + roleKey));
        });
        _user.roleKeys = tempRoleKeys;
        _user.roleObjects = tempRoleObjects;
      }
      return _user;
    });
  }

As for the Template

<h2>Name: {{ (user | async)?.name }} roles</h2>

<ul *ngFor="let roleObject of (user | async)?.roleObjects">
    <li><a [routerLink]="['/role/'+(roleObject | async)?.$key]">{{ (roleObject | async)?.name }}</a></li>
</ul>

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

Implementing dynamic form fields in Angular 2 to efficiently store user input in a database

Currently, I am involved in a project using Angular 2. The task is to include fields with data from the database (specifically rows with the field value 'test8'). If users want to add new fields and values, they need to click the "Add new row" bu ...

Issue with font-size changes using css variables in Angular not updating in browser for specific fields

Utilizing CSS variables, I have implemented a feature that allows users to adjust the font size to small, medium, or large. While this functionality works correctly for most fields, there are certain instances where the value is applied but not displayed. ...

Ways to implement a filter pipe on a property within an array of objects with an unspecified value

Currently, I'm tackling a project in Angular 8 and my data consists of an array of objects with various values: let studentArray = [ { Name: 'Anu', Mark: 50, IsPassed: true }, { Name: 'Raj', Mark: 20, IsPassed: false }, { Na ...

The unexpected identifier 'express' was encountered in the import call, which requires either one or two arguments

I'm in the process of constructing an express server using typescript and Bun. Recently, I completed my register route: import express from "express"; const router = express.Router(); router.get('/registerUser',(_req:express.Reque ...

Angular: merging multiple Subscriptions into one

My goal is to fulfill multiple requests and consolidate the outcomes. I maintain a list of outfits which may include IDs of clothing items. Upon loading the page, I aim to retrieve the clothes from a server using these IDs, resulting in an observable for e ...

Tips for creating Junit tests for a CDK environment

As a newcomer to CDK, I have the requirement to set up SQS infrastructure during deployment. The following code snippet is working fine in the environment: export class TestStage extends cdk.Stage { constructor(scope: cdk.Construct, id: string, props: ...

Issues preventing Angular2 project from being operational

My angular 2 project was running smoothly on my ubuntu machine until I encountered this error. Strangely, just 5 minutes ago it was working fine. The issue arose after I ran another ionic2 project and now the angular project is throwing the following err ...

What is the best way to use Immer to update Zustand state when incorporating objects that are added through a controlled form using React-Hook-

Having some trouble with integrating Zustand and Immer using React-Hook-Form. My goal is to capture a series of values from a form, store them in a list, and allow for the addition of new objects to that list. In this scenario, the user inputs data for a ...

Differing preferences for indentation styles can lead to conflicting prett

My eslint setup is as follows: { "env": { "es2020": true, "jest": true }, "extends": [ "eslint:recommended", "plugin:react/recommended", "plugin:import/recommended&q ...

Ways to access a property within an object using TypeScript

Can you help me extract the "attributes" array from this object and store it in a new variable? obj = { "_id": "5bf7e1be80c05307d06423c2", "agentId": "awais", "attributes": [ // that array. { "created ...

Configuring modules using Sass, CSS-Modules, Webpack, React, and TypeScript

I'm facing an issue with extracting types from my .scss files. I've tried various configurations and solutions, but nothing seems to work. Specifically, my goal is to utilize modules in a React app with TypeScript. Below is my webpack configura ...

The issue of Angular child components rendering before receiving parent data

My current challenge involves a parent component (app.component) making an http request, storing the result in this.stats and then passing it as a prop to the child component (progression.component). The issue arises when my child component tries to render ...

Is "await" considered as a reserved word in ReactJS when using TypeScript?

I am trying to implement async await in my code, but I keep getting an error that says await is a reserved word. Here is the snippet of my code: public componentDidMount() { this.startDrag(); } private startDrag = async () => { const eleme ...

What are some ways to customize the functionality of the data table filter in Angular Material?

Attempting to use the filter feature in Angular Material Data Table: When searching for "MATCHED", both "MATCHED" and "UNMATCHED" are displayed in the status column of the table. It seems this is due to the data object being reduced and concatenated befo ...

The Jasmine test is having trouble locating the imported variable

In my Angular project, I have a class set up as follows: import { USERS } from "./data/users"; // imports an Array of Objects export class User { constructor(name: string) { const user = USERS.find(e => e.name === name); } ... } Every ...

Disabling eslint does not prevent errors from occurring for the unicorn/filename-case rule

I have a file called payment-shipping.tsx and eslint is throwing an error Filename is not in camel case. Rename it to 'paymentShipping.tsx' unicorn/filename-case However, the file needs to be in kebab case since it's a next.js page that s ...

Install NPM without changing directories to the folder

Currently, I am using Windows Powershell and a pipeline to create the package for an application deployment. Here is the pipeline setup: https://i.stack.imgur.com/am2iR.png My current obstacle revolves around the "npm install" command, as I want to avoid ...

Optimizing my AngularJS bundle is pushing me towards upgrading to Angular 5

Regarding my AngularJS application, it was initially created using 'yo angular-fullstack' with JS scripting instead of TS. It is functional but experiencing performance and user experience issues. The deployment is on AWS ElasticBeanstalk nano i ...

Could it be that the Angular query is not returning any data? Or perhaps the issue lies with the dropdown selection not retrieving the data. It's possible that there may be a

I am facing an issue where I am not receiving the complete data from my form query. The query includes a search and mat select dropdown. I need both the selected values back in order to filter elements based on them. However, I am only getting the 'ti ...

Angular 2 - Implementing click event functionality to add an item

I've searched for a solution to this before, but the best answer I could find was from 9 months ago: here and it doesn't work with the latest Angular version. Is there a way to add a new item (<li> or any other) to my HTML with a simple cl ...