Encountering a situation where the data retrieved from Firestore in Angular TypeScript is returning as

I am encountering an issue with retrieving the eventID value from my Events collection in Firestore. Although I am able to successfully display all the events in my app, I require the eventID for additional functionalities.

As someone new to TypeScript and Angular, I am struggling to understand why this functionality is not working as expected.

Inside the auth function, when I log the userid variable, it retrieves the value correctly. However, outside the function, it returns undefined.

Similarly, when I log the entire eventList variable which stores information from Firestore, it logs all the details. But attempting to retrieve specific values like this.eventList.eventID or this.eventList.title results in undefined.

What am I missing here?

Here is the relevant code snippet:

import { Component, OnInit } from '@angular/core';
import { AngularFirestore, AngularFirestoreCollection, AngularFirestoreDocument } from '@angular/fire/compat/firestore';
import { Observable } from 'rxjs/Observable';
import { AuthService } from '../auth.service';
import { Router } from '@angular/router';
import { async } from '@firebase/util';

export class Tab1Page implements OnInit {

  public eventList;
  public userid;
  
  constructor(private firestore: AngularFirestore, public fAuth: AuthService, public router: Router) {}

  ngOnInit() {
    this.fAuth.firebaseAuth.user.subscribe(res => {
      this.userid = res.uid; //current logged in user id

      //fetch only events created by the logged-in user
      this.firestore.collection('Events', ref => ref.where("eventCreator", "==", this.userid)).valueChanges().subscribe(event => { 

        this.eventList = event;

        console.log(this.eventList); //logs all the info from firestore
        console.log(this.eventList.eventID); //logs undefined
        console.log(this.userid); //logs the userid
      });
    });
    
    console.log(this.userid); //logs undefined
  }
}

Answer №1

To avoid issues with undefined data responses in nested subscribes, you can utilize the RxJS switchMap() operator. This allows you to pass the result of the outer observable from the fAuth.firebaseAuth.user observable to the inner observable (this.firestore.collection..). By doing this, you can handle the event list from the streamed response of the inner observable all within a single subscription:

Here is an example (assuming the structure of your event data - it could be an array or a class/interface containing an array, so I have used any as the response type):

this.fAuth.firebaseAuth.user
.pipe(
    switchMap((res: any) => {
        this.userid = res.uid; //current logged in user id

        //fetch only events created by the current user
        const eventListObservable: Observable<any> =                 
            this.firestore.collection('Events',ref => 
                ref.where("eventCreator","==",res.uid))
                .valueChanges()
                .pipe(
                    map((event: any) =>
                    {             
                        this.eventList = event;
 
                        console.log(event); //logs all the info from firestore
                        console.log(event.eventid); //logs event id
                        console.log(user.id); //logs the userid

                        return event;
                    })             
                 );
        return eventListObservable;
    })
)
.subscribe();

It's a good practice to assign the above to a subscription and release it later in the ngDestroy() handler.

A common issue arises when trying to access variables outside the subscribe() block, as discussed in this question. To address this, consider using:

  1. An async pipe in the component's HTML template. (Convert the variable to an Observable first).
  2. Another RxJS method like combinelatest() to subscribe to observables concurrently and manage them once they all have results ready.
  3. Accessing the variable in another event handler from the HTML template.

For experimenting with nested observables, start with simple mock services before connecting to live services. Also, refer to a helpful site here for more insights on using RxJS in various scenarios.

Answer №2

When

console.log(this.userid) // logs undefined

It seems that @MikeOne mentioned that the functions inside subscribe are asynchronous. This means they will be executed at a later time. Therefore, when

console.log(this.userid)//logs undefined
is called, this.userid = res.uid; has not been executed yet.

Regarding

console.log(this.eventList.eventID) // logs undefined

It appears that this.eventList is an array. You might want to try accessing elements like this.eventList[0].eventID or iterate through the array to access each element individually.

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 Node.js microservices with AWS Cognito leveraging Amplify's best practices

I am currently working on developing a Node.js API that is broken down into several small APIs (microservices) communicating with each other through requests and responses. Additionally, I am utilizing Angular for the frontend. My next step is to enhance ...

I'm curious as to why it's requesting an ID in the newTask function. I followed the tutorial exactly and encountered the same error

An issue has occurred in the project, displaying the following error: Error: src/app/components/add-task/add-task.component.ts:32:25 - error TS2345: Argument of type '{ text: string; day: string; reminder: boolean; }' is not assignable to paramet ...

What steps can I take to enhance the quality of my PDF files? Currently, I am utilizing Jspdf in conjunction with html

My current challenge involves generating a PDF file from my application. Although I am able to create a PDF, the quality is not up to par. When I download the PDF, I notice some discrepancies in text quality. While it's not terrible, it's also n ...

How can TypeScript rules be incorporated into a Next.js project without compromising next/core-web-vitals?

In my current NextJS project which is in typescript, I have the following configuration in my .eslintrc.json: { "extends": "next/core-web-vitals" } Now, I want to include additional typescript rules, such as enforcing the rule of n ...

Issue occurs where the system is unable to recognize a defined variable, despite it being clearly defined

I keep encountering an error message stating that my variable is not defined, even though I have clearly defined it just a few lines above where the error occurs. The reason behind this error is baffling to me, as I cannot identify any potential triggers ...

Steps for passing a JSON object as a PathVariable in a Spring controller

Currently, I am in the process of developing a spring application using AngularJS. My goal is to pass a JSON object as a @PathVariable to the spring controller. However, with my existing code, I am facing an issue where when attempting to pass the JSON obj ...

Having trouble accessing a variable from the material theme in Angular 7

Currently, I am working with Angular 7.0.3 and endeavoring to establish an scss variable with the primary color of my material theme. // src/styles/_variables.scss @import "~@angular/material/theming"; @include mat-core(); $app-primary: mat-palette($mat-i ...

JavaScript Definition File for TypeScript

Within my repertoire is a Js File, comprised of a leaflet plugin, Js: L.BingLayer = L.TileLayer.extend({ options: { subdomains: [0, 1, 2, 3], type: 'Aerial', attribution: 'Bing', culture: '' }, initialize ...

Resizing cell height in an HTML table is not supported by Angular 5

In my angular application, I've implemented a component that represents a basic HTML table. However, I'm facing an issue with reducing the height of cells within the table. It seems like my CSS styling is not affecting the display as desired. He ...

Vue is encountering difficulties resolving the index.vue file located in the parent directory

Having trouble importing a component from the path folder, I keep encountering an error message stating "Cannot find module './components/layout/Navbar'. Vetur(2307)". This is how I am attempting to import the component: import Navbar from "./c ...

Is it possible to implement cross-field validation with Angular 2 using model-based addErrors?

Currently, I am working on implementing cross-field validation for two fields within a form using a reactive/model based approach. However, I am facing an issue regarding how to correctly add an error to the existing Error List of a form control. Form: ...

Transfer a selection of image files from your device to a storage bucket using firebase-admin

How can I upload an entire directory to a Firebase bucket using firebase-admin? var admin = require("firebase-admin"); var serviceAccount = require("path/to/serviceAccountKey.json"); admin.initializeApp({ credential: admin.credential.cert(serviceA ...

Comparing tick and flushMicrotasks in Angular fakeAsync testing block

From what I gathered by reading the Angular testing documentation, using the tick() function flushes both macro tasks and micro-task queues within the fakeAsync block. This leads me to believe that calling tick() is equivalent to making additional calls pl ...

Change the term to its corresponding translation

I have developed an Ionic Multilingual App that includes a select feature. Within this select, choosing a specific option disables certain page elements. However, I am facing an issue where one of the elements needs to change its text based on the selected ...

TypeScript generic types allow you to create reusable components that

function genericIdentity<T>(arg: T): T { return arg; } let myGenericIdentity: <U>(arg: U) => U = genericIdentity; I see that the 'genericIdentity' function is accepting an argument of a generic type. However, I am unsure about ...

Determine the type of input and output based on another argument

When working with a function that takes an object of either TypeA or TypeB, the first parameter is used to specify the type of the object and the returned type depends on this first parameter. The issue arises in TypeScript where the type of the object is ...

angularslideables retro animation

I'm currently using the AngularSlideables library to toggle a modal within my Ionic project. You can check out a functional example in this fiddle: http://jsfiddle.net/3sVz8/19/ However, I am facing an issue where the initial height is set to 100% i ...

Angular component injected with stub service is returning incorrect value

While attempting to write tests for my Angular component that utilizes a service, I encountered an issue. Despite initializing my userServiceStub property isLoggedIn with true, the UserService property appears false when running the tests. I experimented ...

"When attempting to render a Node inside the render() method in React, the error message 'Objects are not valid as a React child' is

On my webpage, I have managed to display the following: export class OverworldComponent extends React.Component<OverworldComponentProps, {}> { render() { return <b>Hello, world!</b> } } However, instead of showing Hello, ...

Is there a way to enable Tail Recursion Optimization in TypeScript?

const isPositive = (n: number) => n > 0; function fitsIn(dividend: number, divisor: number, count: number, accum: number): number { if (accum + divisor > dividend) { return count; } return ...