Encountering an error when attempting to show user details on a webpage using Angular and Ionic with Promise functionality

On my app's AccountSettingsPage, I am fetching user data from a SQLite DB and displaying it on an Ionic page. However, I encountered the following error:

Error:

TypeError: Cannot read property 'name' of undefined
    at Object.eval [as updateRenderer] (ng:///AppModule/AccountSettingsPage.ngfactory.js:87:37)
    at Object.debugUpdateRenderer [as updateRenderer] (http://192.168.0.4:8100/build/vendor.js:15109:21)
    at checkAndUpdateView (http://192.168.0.4:8100/build/vendor.js:14223:14)
    at callViewAction...

account-settings.ts

export class AccountSettingsPage {

  currentUser: User;

  constructor(private navCtrl: NavController, private navParams: NavParams, private userProvider: UserProvider) {
    this.getCurrentUserDetails("<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="5332311330377d303c3e">[email protected]</a>");
  }

  getCurrentUserDetails(email: string) {
    this.userProvider.getUserByEmail(email)
      .then((currentUser: User) => {
        this.currentUser = currentUser;
        console.log("data: " + JSON.stringify(currentUser));
      })
      .catch(e => console.error(JSON.stringify(e)));
  }

}   

user.ts (UserProvider)

getUserByEmail(email: string): Promise<User> {
    return this.databaseProvider.getDatabase().then(database => {
      return database.executeSql(SQL_SELECT_USER_BY_EMAIL, [email])
        .then((data) => {
          let user: User;
          //loop through all the records and populate the user object. Should be only 1
          for (let i = 0; i < data.rows.length; i++) {
            user = {
              id: data.rows.item(i).id,
              name: data.rows.item(i).name,
              email: data.rows.item(i).email,
              password: data.rows.item(i).password,
              confirmPassword: data.rows.item(i).password,
              phone: data.rows.item(i).phone,
              street1: data.rows.item(i).street1,
              street2: data.rows.item(i).street2,
              city: data.rows.item(i).city,
              state: data.rows.item(i).state,
              zip: data.rows.item(i).zip,
              active: data.rows.item(i).active
            };
          }
          //return the populated user object back
          return user;
        });

    });
  }

account-settings.html (Page)

<ion-header>
  <ion-navbar>
    <ion-title>Account Settings</ion-title>
  </ion-navbar>
</ion-header>

<ion-content padding>
  <ion-list>
    <ion-label>Name: {{currentUser.name}}</ion-label>
    <ion-label>Email: {{currentUser.email}}</ion-label>
    <ion-label>Password: {{"*****"}}</ion-label>
    <ion-label>Phone: {{currentUser.name}}</ion-label>
    <ion-label>Street 1: {{currentUser.street1}}</ion-label>
    <ion-label>Street 2: {{currentUser.street2}}</ion-label>
    <ion-label>City: {{currentUser.city}}</ion-label>
    <ion-label>State: {{currentUser.state}}</ion-label>
    <ion-label>Zip: {{currentUser.zip}}</ion-label>
  </ion-list>
  <button ion-button (click)="logout()">Logout</button>
</ion-content>

Answer №1

When your view is created, the currentUser in your controller starts off as undefined until it is fetched from the database.

To prevent displaying anything if currentUser is undefined, you can add an *ngIf directive to your HTML.

<ion-content *ngIf="currentUser" padding>
  <ion-list>
    <ion-label>Name: {{currentUser.name}}</ion-label>
    <!-- ... -->
  </ion-list>
  <button ion-button (click)="logout()">Logout</button>
</ion-content>

Make sure to update the UserProdiver so that it actually returns a value from the promise:

getUserByEmail(email: string): Promise<User> {
  return new Promise((resolve, reject) => {
    this.databaseProvider.getDatabase().then(database => {
      database.executeSql(SQL_SELECT_USER_BY_EMAIL, [email])
        .then((data) => {
          let user: User;
          //loop through all the records and populate the user object. Should be only 1
          for (let i = 0; i < data.rows.length; i++) {
            user = {
              id: data.rows.item(i).id,
              name: data.rows.item(i).name,
              email: data.rows.item(i).email,
              password: data.rows.item(i).password,
              confirmPassword: data.rows.item(i).password,
              phone: data.rows.item(i).phone,
              street1: data.rows.item(i).street1,
              street2: data.rows.item(i).street2,
              city: data.rows.item(i).city,
              state: data.rows.item(i).state,
              zip: data.rows.item(i).zip,
              active: data.rows.item(i).active
            };
          }
          //return the populated user object back
          return resolve(user);
        });
    });
  });
}

Answer №2

To ensure that the user data is displayed only after successful loading of currentUser, you can utilize the *ngIf structural directive. Since currentUser may not be initialized with default values for all properties and is loaded asynchronously, using *ngIf will prevent accessing properties of an undefined object until it has been successfully loaded:

<ion-content *ngIf=“currentUser” padding>
  <ion-list>
    <ion-label>Name: {{currentUser.name}}</ion-label>
    <ion-label>Email: {{currentUser.email}}</ion-label>
    <ion-label>Password: {{"*****"}}</ion-label>
    <ion-label>Phone: {{currentUser.phone}}</ion-label>
    <ion-label>Street 1: {{currentUser.street1}}</ion-label>
    <ion-label>Street 2: {{currentUser.street2}}</ion-label>
    <ion-label>City: {{currentUser.city}}</ion-label>
    <ion-label>State: {{currentUser.state}}</ion-label>
    <ion-label>Zip: {{currentUser.zip}}</ion-label>
  </ion-list>
  <button ion-button (click)="logout()">Logout</button>
</ion-content>

You can enhance this by incorporating an else statement in combination with *ngIf to display a loading message while the data is being fetched:

<ion-content *ngIf=“currentUser; else loadingCurrentUser” padding>
  <ion-list>
    <ion-label>Name: {{currentUser.name}}</ion-label>
    <ion-label>Email: {{currentUser.email}}</ion-label>
    <ion-label>Password: {{"*****"}}</ion-label>
    <ion-label>Phone: {{currentUser.phone}}</ion-label>
    <ion-label>Street 1: {{currentUser.street1}}</ion-label>
    <ion-label>Street 2: {{currentUser.street2}}</ion-label>
    <ion-label>City: {{currentUser.city}}</ion-label>
    <ion-label>State: {{currentUser.state}}</ion-label>
    <ion-label>Zip: {{currentUser.zip}}</ion-label>
  </ion-list>
  <button ion-button (click)="logout()">Logout</button>
</ion-content>

<ng-template #loadingCurrentUser>
  Loading...
</ng-template>

Additionally, it is recommended to make the API call within the Angular lifecycle hook OnInit rather than the constructor for proper initialization:

export class AccountSettingsPage implements OnInit {
  currentUser: User;

  constructor(private navCtrl: NavController, private navParams: NavParams, private userProvider: UserProvider) {}

  ngOnInit(): void {
    this.getCurrentUserDetails("<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="dbbab99bb8bff5b8b4b6">[email protected]</a>");
  }

  getCurrentUserDetails(email: string) {
    this.userProvider.getUserByEmail(email)
      .then((currentUser: User) => {
        this.currentUser = currentUser;
        console.log("data: " + JSON.stringify(currentUser));
      })
      .catch(e => console.error(JSON.stringify(e)));
  }
}

Hope this explanation helps!

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

Live server code does not update with changes made in Angular

https://i.stack.imgur.com/Yo6Y8.png In the screenshot above, you can see my changes. I simply modified the text to read Download PDF, replacing what was there previously. Instead of the folder shown here, I used the code from this compiled file: https:// ...

Having trouble with $ionicModal throwing an undefined error?

I am attempting to implement a modal window upon clicking, I had successfully used the code in a previous project but encountering an error when trying it in a new project: > TypeError: Cannot read property 'show' of undefined at > Scope.$ ...

Difficulty Encountered While Deploying Mean Stack Application on Heroku

I am embarking on my first journey of building a MEAN stack application, and I successfully created it locally. However, when attempting to host it on Heroku, things didn't go as planned. After researching online, I learned that both Angular and Expre ...

Is it possible to toggle between namespace and class using parentheses?

While working with older javascript code, I stumbled upon the following snippet: // module1.js class Class { constructor() { console.log('hello') } } const exported = { Class: Class, } module.exports = exported This code is then ...

connecting and linking template content with an Observable

I have a CRUD page that needs to be updated after every operation. I have implemented Observable and the CRUD functions (specifically Add and Delete) are working fine, but I need to manually refresh the page to see the changes reflected. After trying to ...

Is your Angular app missing i18next translations?

Can Angular's i18next provider be configured to hide any value when the key is not defined? The issue arises when there is no translation defined for a specific key like my:key. I want to display an empty string in the template instead of showing the ...

The specified type of 'Observable<{ } | IProduct[]>' cannot be matched with the type of 'Observable<IProduct[]>'

Currently enrolled in the Angular 6 course by Deborah Kurata I have completed the Observables module, but encountered an error in my products.service. I came across this solution, but I have already tried it and believe it may not be relevant to the issu ...

Ways to sort mat-select in alphabetical order with conditional names in options

I am looking to alphabetically order a mat-select element in my Angular project. <mat-select [(ngModel)]="item" name="item" (selectionChange)="changeIdentificationOptions($event)"> <mat-option *ngFor="let item of items" [value]="item"> ...

Utilizing MUI for layering components vertically: A step-by-step guide

I am looking for a way to style a div differently on Desktop and Mobile devices: ------------------------------------------------------------------ | (icon) | (content) |(button here)| ----------------------------------------- ...

Skip waiting for all resolves to complete before showing the views in ui-router

My current setup involves using ui-router to load various subviews within a certain state. However, some of these views require resources that have a long resolution time. I want to display the other views as soon as they are ready. This is how I am fetch ...

Receive a notification when the div element stops scrolling

I am attempting to replicate Android's expandable toolbar within an Angular component. My HTML code appears as follows: <div (scroll)="someScroll($event)"> <div class="toolbar"></div> <div class="body"></div> </d ...

ngclass is not functioning properly when used with dynamically generated components

I am experiencing an issue with the components I create using createComponent. Although some of them function properly, others lack the appropriate CSS classes. Despite using a function and [ngClass] to set the classes, they do not appear when inspected in ...

How come Typescript allows me to generate intersection types that seem impossible?

Despite being unimplementable, the type definition below does not trigger any warnings from the compiler. // No type error type impossible = 0 & string[] & 'anything' An item cannot simultaneously be a number, a string[], and a stri ...

Angular service encounters NotYetImplemented error due to DOCUMENT injection token in SSR

I have a unique Angular SSR app with a special service that utilizes the document. I cleverly utilize the DOCUMENT injection token to provide this essential document for dependency injection. To take a peek at my innovative approach, check out my repo here ...

Utilizing a monorepo approach enables the inclusion of all *.d.ts files

Scenario: In our monorepo, we have 2 workspaces: foo and bar. foo contains the following files: src/file.ts src/@types/baz.d.ts The bar workspace is importing @monorepo/foo/src/file. While type-checking works for the foo workspace, it does not work fo ...

What is my strategy for testing a middleware that accepts arguments?

Here is the middleware I am working with: function verifyKeys(expectedKeys: string[], req: Request): boolean{ if (expectedKeys.length !== Object.keys(req.body).length) return false; for (const key of expectedKeys) { if (!(key in req.body)) return ...

Definition for the type react-navigation-v6 <Stack.Group>

I'm having trouble figuring out the proper type definition for a Stack group that includes screens (refer to TestStack.Group and the nested TestStack.Screen). The navigation stack: const TestStack = createNativeStackNavigator<TestStackParamList> ...

What is the best way to set up the parser and plugins using ESLint's updated flat configuration?

How can ESLint be configured using the new "flat config" system (specifically with the eslint.config.js file) to work seamlessly with both @typescript-eslint/eslint-plugin and /parser? I have been struggling to make ESLint's new configuration system ...

What happens when two style() functions are passed into the query() function for Angular Animations?

As someone who is relatively new to angular animations, I have reviewed the angular.io animation documentation multiple times in order to grasp how everything functions. While I believe I have a decent understanding, there are certain scenarios that the do ...

Encountered a runtime error while processing 400 requests

Current Situation: When authenticating the username and password in my Ionic 2 project using WebApi 2 token authentication, a token is returned if the credentials are correct. However, a 400 bad request error is returned if the credentials are incorrect. ...