使用 Promise 在 Angular 和 Ionic 的页面上显示用户信息时出现以下错误

Posted

技术标签:

【中文标题】使用 Promise 在 Angular 和 Ionic 的页面上显示用户信息时出现以下错误【英文标题】:Getting following error while displaying user information on a page in Angular and Ionic with Promise 【发布时间】:2019-05-30 15:15:16 【问题描述】:

在我的应用程序和AccountSettingsPage 上,我从SQLite DB 获取用户数据并将其显示在Ionic 页面上。但是,我收到此错误。

错误:

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 (http://192.168.0.4:8100/build/vendor.js:14569:21)
    at execComponentViewsAction (http://192.168.0.4:8100/build/vendor.js:14501:13)
    at checkAndUpdateView (http://192.168.0.4:8100/build/vendor.js:14224:5)
    at callViewAction (http://192.168.0.4:8100/build/vendor.js:14569:21)
    at execEmbeddedViewsAction (http://192.168.0.4:8100/build/vendor.js:14527:17)
    at checkAndUpdateView (http://192.168.0.4:8100/build/vendor.js:14219:5)
    at callViewAction (http://192.168.0.4:8100/build/vendor.js:14569:21)

account-settings.ts

export class AccountSettingsPage 

  currentUser: User;

  constructor(private navCtrl: NavController, private navParams: NavParams, private userProvider: UserProvider) 
    this.getCurrentUserDetails("ab@cd.com");
  

  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(用户提供者)

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(页面)

<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.street1</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>

【问题讨论】:

你真的是指data.rows.item(i)吗?假设您循环通过data.rows 使用data.rows[i] 会更有意义,但是根本不循环并只使用data.rows[0] 的属性会更有意义(如果存在;如果不存在则抛出) . 我还是 JS 和移动开发领域的新手。将尝试您的建议@Roamer-1888 【参考方案1】:

在创建视图时,控制器中的 currentUserundefined,直到从数据库中获取。

如果 currentUser 未定义,您应该在 html 中添加 *ngIf 指令以防止显示。

<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>

然后更新 UserProdiver 以从承诺中实际返回一个值:

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);
        );
    );
  );

【讨论】:

【参考方案2】:

尝试使用*ngIf 仅在currentUser 成功加载后显示用户数据。由于currentUser 未使用您正在渲染和异步加载的所有这些属性的默认值进行初始化,因此您可以使用此结构指令来避免尝试访问未定义对象的这些属性,直到成功加载/解析:

<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.name</ion-label>
    <ion-label>Street 1: currentUser.street1</ion-label>
    <ion-label>Street 2: currentUser.street1</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>

您可以通过使用带有*ngIfelse 语句来扩展此概念,以在数据加载时显示加载消息或类似信息:

<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.name</ion-label>
    <ion-label>Street 1: currentUser.street1</ion-label>
    <ion-label>Street 2: currentUser.street1</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>

最后考虑在Angular生命周期钩子OnInit而不是构造函数中执行这个调用,这是初始化任务的理想位置,例如这个数据库调用:

export class AccountSettingsPage implements OnInit 
  currentUser: User;

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

  ngOnInit(): void 
    this.getCurrentUserDetails("ab@cd.com");
  

  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)));
  

希望对您有所帮助!

【讨论】:

以上是关于使用 Promise 在 Angular 和 Ionic 的页面上显示用户信息时出现以下错误的主要内容,如果未能解决你的问题,请参考以下文章

Angular2 Observable 和 Promise

在Angular 2中拒绝Promise时未处理的Promise拒绝[重复]

在 Angular 中,如何在使用 async/await 时处理 Promise 拒绝

Promise.all 的 then() 函数在 Promise 完成之前执行 - Ionic/Angular

angular ui-router 1.0.3 和 angular.js 1.6.4 似乎使用了错误的 Promise 类型?

使用 Angular 1 应用程序在 Typescript 中管理 ES6/2015 Promise