Why is my Angular app displaying outdated data from Firebase when navigating between pages?

Currently, I am dealing with an Angular 9 application that is hosted on Firebase and utilizes Firestore for its data storage. There is a perplexing issue that I haven't been able to figure out completely despite simplifying the app extensively. I will attempt to elucidate the problem below.

About the Application: The application consists of two main pages - Homepage and Transactions page. Both pages retrieve data from the "transactions" collection in Firebase. However, the homepage should display the 4 most recent transactions (sorted by date in descending order), while the Transactions page needs to show the 10 most profitable transactions (sorted by amount in descending order). Currently, I am logging the data to the console for debugging purposes. Before logging the data, there is some minor data manipulation happening as well (refer to code snippet below).

The Challenge: Upon initially loading the Homepage, I am able to view the 4 most recent transactions in the console, which is expected. However, upon navigating to the Transactions page, for a brief moment, the console displays the same 4 recent transactions again, although they are supposed to be exclusive to the Homepage. After this quick display, it then correctly logs the 10 most profitable transactions.

The Code: Below is a snippet of the code used for home.page.ts:

 insert code here...

The code for transaction.page.ts follows a similar structure:

 insert code here...

The Outcome: A summary of what is logged to the console during each stage of interaction is as follows

  1. Upon initial entry to the Home page (displaying 4 rows):
insert code output here...
  1. Transition to the Transactions page:
insert code output here...

The Enigma: Why does the console re-display the same 4 rows from the Homepage when accessing it after navigating away?

Answer №1

On the transactions page, you may observe results appearing twice. This occurrence is most likely due to the valueChanges function retrieving data from the in-memory cache of Firestore first for a rapid response before fetching the actual data. In this scenario, 4 rows are initially cached upon being retrieved on the home page and subsequently accessed from the cache on the transactions page.

Answer №2

It seems like the issue lies here:

loadHomeData() {
  this.txSubscription = this.firestore
  ...
  .subscribe(rows => {
    ...
  })
}

ngOnInit() {
  this.afAuth.onAuthStateChanged(() => {
    this.loadHomeData();
  })
}

ngOnDestroy() {
  this.txSubscription.unsubscribe();
}

You are correctly handling unsubscribing. However, when onAuthStateChanged fires again, the initial subscription is lost and cannot be unsubscribed. Consider using the switchmap operator with onAuthStateChanged to resolve this issue. Here's an example implementation:

this.subscription = this.af.authState.pipe(
  switchMap(auth => {
    if(auth !== null && auth !== undefined){
      return   this.firestore.collection('transactions', ref => ref.orderBy('profitEur', 'desc').limit(10)).valueChanges())
    } else{
      throw "Not loggedin";
    }
).subscribe(...)

Answer №3

Perhaps the issue is arising due to

this.afAuth.onAuthStateChanged()

being triggered twice.

Instead of constantly checking for the authentication state in every component, you can simply subscribe to the auth state in app.component.ts. If a user is not authenticated or if the authentication state changes, they will be redirected to the login page; otherwise, they will be directed to home.page.ts.

export class AppComponent {
  constructor(private readonly auth: AngularFireAuth, private router: Router) {
    this.auth.authState.subscribe(response => {
      console.log(response);
      if (response && response.uid) {
        this.router.navigate(['dashboard', 'home']); // Route to Home page
      } else {
        this.router.navigate(['auth', 'login']); // Route to Login Page
      }
    }, error => {
      this.auth.signOut();
      this.router.navigate(['auth', 'login']); // Route to Login Page
    });
  }
}

In your home.component.ts and transaction.page.ts, there's no need to check the authentication state.

  • home.component.ts
 txSubscription: Subscription;

  constructor(
    public afAuth: AngularFireAuth,
    private readonly firestore: AngularFirestore
  ) { }

  // Function to get the 4 most recent transactions
  async getRecentTransactions() {
    this.txSubscription = this.firestore
      .collection('transactions', ref => ref.orderBy('date', 'desc').limit(4))
      .valueChanges()
      .subscribe(rows => {
        this.recentTransactions = [];

        rows.forEach(row => {
          let jsonData = {};
          jsonData['ticker'] = (row['ticker'].length <= 10 ? row['ticker'] : row['ticker'].substring(0, 10) + '...');
          jsonData['date'] = formatDate(row['date'].toDate(), 'dd/MM/y', 'en');
    
          jsonData['amount'] = prefix + formatNumber(row['netAmount'], 'be', '1.2-2');
    
          this.recentTransactions.push(jsonData);
        })

        console.log("home page", this.recentTransactions);
      })
  }

  ngOnInit() {
      this.getRecentTransactions();
  }

  ngOnDestroy() {
    this.txSubscription.unsubscribe();
  }
  • transaction.page.ts
 txSubscription: Subscription;

  constructor(
    public afAuth: AngularFireAuth,
    private readonly firestore: AngularFirestore
  ) { }

  // Function to load the data for the home page
  loadHomeData() {
    this.txSubscription = this.firestore
      .collection('transactions', ref => ref.orderBy('profitEur', 'desc').limit(10))
      .valueChanges()
      .subscribe(rows => {
        this.resultRows = [];

        rows.forEach(row => {
          this.resultRows.push(row['ticker'].slice(0, 8));
        });

        console.log("transaction page", this.resultRows);
      })
  }

  ngOnInit() {
      this.loadHomeData();
  }

  ngOnDestroy() {
    this.txSubscription.unsubscribe();
  }

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

Various redirects based on multiple referrers

Here is the code I have for redirecting based on the referer: document.addEventListener('DOMContentLoaded', function() { console.log(isMobile); var referrer = document.referrer; if(referrer.indexOf('site1.com') !== -1 || referrer ...

Issue with Vue.js: document.querySelector is returning a null value even though the element clearly exists

I'm currently working on implementing a responsive navbar following Kevin Powell's tutorial, but I've run into an issue. For some reason, when I try to select the element with the class 'primary-navigation' using 'const primar ...

Show an HTML image encoded in base64 from its origin

Is there a way to embed a base64 image in HTML without having to paste the entire code directly into the file? I'm looking for a more efficient method. For example: <div> <p>Image sourced from an online repository</p> <img src=" ...

The directive attribute in AngularJS fails to connect to the directive scope

I have been attempting to pass an argument to a directive through element attributes as shown in the snippet below: directive app.directive('bgFluct', function(){ var _ = {}; _.scope = { data: "@ngData" } _.link = function(scope, el ...

Instructions for implementing this script in HTML and JavaScript: utilize the clone() function

I came across this code snippet here function displaytickets(){ var $panel = $('<div/>').addClass('col-xs-3 panel panel-default') $panel.append($('<div><h3 class="panel-title">Title</h3></div>&a ...

Turn the camera to focus on the chosen object using three.js

I've been working on designing a map and I'm trying to achieve a specific functionality. When I select any geometry, I want the object to be positioned at the center of the viewport with the camera looking directly at it. Despite searching extens ...

React.js implementation of individual checkboxes for every row in a table

My functional component contains a table with multiple rows as shown below: import React from "react"; import Checkbox from "@material-ui/core/Checkbox"; function Table({ data }) { const [checked, setChecked] = useState(false); ...

The placeholder text is not displaying with bullets in Internet Explorer. However, it is functioning correctly in Chrome

I need assistance displaying the placeholder text in IE8 as shown below: "Any relevant reference numbers, such as Direct Debits: - Name of the Branch (if applicable) - What was the original problem - Date the problem occurred " While it appears correct ...

In TypeScript, both 'module' and 'define' are nowhere to be found

When I transpile my TypeScript using "-m umd" for a project that includes server, client, and shared code, I encounter an issue where the client-side code does not work in the browser. Strangely, no errors are displayed in the browser console, and breakpoi ...

What is the best way to ensure that this form field remains hidden when the page is loaded?

In my Django project, I have a form that should only display the entity name on page load. However, it is currently showing both the entity name and quote text fields. The quote text field should only be visible when the entity name is not in the database. ...

Differentiate among comparable values through placement regex

I'm currently tackling a challenge involving regex as I work on breaking down shorthand CSS code for the font property. Here is my progress thus far: var style = decl.val.match(/\s*(?:\s*(normal|italic|oblique)){1}/i); style = style ? style ...

Could an OpaqueToken be assigned using an observable?

I am attempting to establish an opaque token in the providers using an observable. The purpose behind this is that I am retrieving the value through the Http provider (from an external JSON file). This is my current approach: { provide: SOME_ ...

Unpacking data types from an array of classes in TypeScript: A step-by-step guide

I am working on a function that takes an array or rest of Typescript classes as input and resolves, returning their instances. However, I'm struggling to ensure correct typing for it. If I take one class as an example: class Base { isBase = true ...

Retrieve data from the MySQL database based on the search input field and dynamically update the options in the

I'm facing a programming challenge that I perceive to be at an advanced level for me. Currently, I have a custom search field in my registration form. However, I am looking to transform it into a dropdown menu that pulls user values from MySQL databas ...

How can I adjust the scale and position of my image textures in Three.js?

Is there a way to adjust the scale and position of my image textures? The dimensions of my image are 1024px x 1024px. let textureMap = THREE.ImageUtils.loadTexture( 'texture.png' ); https://i.sstatic.net/wKd6f.jpg ...

What is the best way to implement a loop using JQuery?

<script> $(function() { $('.slideshow').each(function(index, element) { $(element).crossSlide({ sleep: 2, fade: 1 }, [ { src: 'picture' + (index + 1) + '.jpg' } ]); }); ...

Getting a specific piece of information from a JSON file

I am encountering an issue with my JSON file collection. When I access it through http://localhost:5000/product/, I can see the contents without any problem. However, when I try to retrieve a specific product using a link like http://localhost:5000/product ...

Exploring the optimal approach for distinguishing between numbers and strings in a JavaScript/Typescript class

I recently encountered a situation with my Typescript/React solution where I defined a property as a number and set the input type to "number", but when the state value was placed in an input field, it would change to a string unless properly handled. In ...

Rotating through elements in timed intervals

After exploring various examples of how to show/hide divs with a JavaScript timeout, I am still unable to resolve my specific issue. I currently have six divs that I want to cycle through sequentially every 10 seconds, starting with div #one. Although my ...

Having trouble running npm start with Express generator

After installing Express Generator according to the instructions on the website, I encountered an issue when trying to run npm start. My Windows system has npm 6.4.1 and node v10.15.3 installed. > [email protected] start C:\Users\ONLINEW ...