首页 > 解决方案 > 无法使用选项卡式页面上的提供程序在 Angular 和 Ionic 中查询数据库

问题描述

我有一个主页,它是一个用Ionic 3和设计的选项卡式页面Angular。它有两个选项卡StatsCalc. 单击 Stats 页面会调用类/组件stats.ts(如下所示)。

该组件使用两个提供程序CropProviderContractProvider它们查询数据库并获取一些记录。这些提供程序在其他页面上运行良好,并且能够成功地从 SQLite DB 获取数据,但是通过选项卡式页面我看到了以下错误。

错误:

Error: Uncaught (in promise): TypeError: Cannot read property 'length' of undefined
TypeError: Cannot read property 'length' of undefined
    at StatsPage.webpackJsonp.168.StatsPage.buildStats (http://192.168.0.5:8100/build/main.js:707:51)
    at new StatsPage (http://192.168.0.5:8100/build/main.js:690:14)
    at createClass (http://192.168.0.5:8100/build/vendor.js:13176:20)
    at createDirectiveInstance (http://192.168.0.5:8100/build/vendor.js:13011:37)
    at createViewNodes (http://192.168.0.5:8100/build/vendor.js:14469:53)
    at createRootView (http://192.168.0.5:8100/build/vendor.js:14358:5)
    at callWithDebugContext (http://192.168.0.5:8100/build/vendor.js:15783:42)
    at Object.debugCreateRootView [as createRootView] (http://192.168.0.5:8100/build/vendor.js:15066:12)
    at ComponentFactory_.create (http://192.168.0.5:8100/build/vendor.js:11963:46)
    at ComponentFactoryBoundToModule.create (http://192.168.0.5:8100/build/vendor.js:4715:29)
    at c (http://192.168.0.5:8100/build/polyfills.js:3:19752)
    at c (http://192.168.0.5:8100/build/polyfills.js:3:19461)
    at http://192.168.0.5:8100/build/polyfills.js:3:20233
    at t.invokeTask (http://192.168.0.5:8100/build/polyfills.js:3:15660)
    at Object.onInvokeTask (http://192.168.0.5:8100/build/vendor.js:5436:33)
    at t.invokeTask (http://192.168.0.5:8100/build/polyfills.js:3:15581)
    at r.runTask (http://192.168.0.5:8100/build/polyfills.js:3:10834)
    at o (http://192.168.0.5:8100/build/polyfills.js:3:7894)
    at e.invokeTask [as invoke] (http://192.168.0.5:8100/build/polyfills.js:3:16823)
    at p (http://192.168.0.5:8100/build/polyfills.js:2:27648)

统计.ts

   @IonicPage()
    @Component({
      selector: 'page-stats',
      templateUrl: 'stats.html',
    })
    export class StatsPage implements OnInit {
      crops: Crop[];
      crop = {} as Crop;
      contracts: Contract[];
      contract = {} as Contract;
      stats = {} as Stats;
      contentEle: any;
      textEle: any;
      @ViewChild('popoverContent', {read: ElementRef}) content: ElementRef;
      @ViewChild('popoverText', {read: ElementRef}) text: ElementRef;

      constructor(public navCtrl: NavController, private popoverCtrl: PopoverController,
                  private cropProvider: CropProvider,
                  private contractProvider: ContractProvider) {
        console.log("Into the stats page........");
        console.log("cropProvider: " + cropProvider);
        console.log("contractProvider: " + contractProvider);
        this.cropProvider.getAllCrops()
          .then((crops: Crop[]) => {
            this.crops = crops;
          })
          .catch(e => console.error(e));

        this.contractProvider.getAllContracts()
          .then((contracts: Contract[]) => {
            this.contracts = contracts;
          })
          .catch(e => console.error(e));

        this.buildStats();
      }

    buildStats() {
        console.log("crops:" + this.crops);
        console.log("contracts:" + this.contracts);

        for (let crop of this.crops) {
          this.stats.cropName = crop.cropName;
          this.stats.grossMarketable = crop.acres * crop.expectedAPH;
          this.stats.aphMarketable = crop.acres * crop.guaranteedAPH;
        }
        console.log("cropName: " + this.stats.cropName);
        console.log("grossMarketable: " + this.stats.grossMarketable);
        console.log("grossMarketable: " + this.stats.aphMarketable);

        for (let contract of this.contracts) {
          this.stats.amountSold = contract.contractTotalBushels;
          this.stats.percentageGross = (this.stats.amountSold / this.stats.grossMarketable) * 100;
          this.stats.percentageAPH = (this.stats.amountSold / this.stats.aphMarketable) * 100;
          this.stats.avgSold = (this.contract.contract1Total + this.contract.contract2Total + this.contract.contract3Total) /
            (this.contract.contract1Price + this.contract.contract2Price + this.contract.contract3Price);
        }
        console.log("amountSold: " + this.stats.amountSold);
        console.log("percentageGross: " + this.stats.percentageGross);
        console.log("percentageAPH: " + this.stats.percentageAPH);
        console.log("avgSold: " + this.stats.avgSold);
        console.log("stats: " + this.stats);
      }

    ngOnInit(): void {
       console.log("Into the ngOnInit page........");
    }
}

主页.html

<ion-tabs color="primary">
  <ion-tab [root]="tab1Root" tabIcon="stats" tabTitle="Stats"></ion-tab>
  <ion-tab [root]="tab2Root" tabIcon="calculator" tabTitle="Calculations"></ion-tab>
</ion-tabs>

主页.ts

@IonicPage()
@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {

  tab1Root = StatsPage;
  tab2Root = CalcPage;

}

控制台日志:

[app-scripts] [23:20:57]  console.log: Into the stats page........
[app-scripts] [23:20:57]  console.log: cropProvider: [object Object]
[app-scripts] [23:20:57]  console.log: contractProvider: [object Object]
[app-scripts] [23:20:57]  console.log: crops:undefined
[app-scripts] [23:20:57]  console.log: contracts:undefined

不知道我在这里错过了什么。我已经在构造函数中注入了它们。

标签: angulartypescriptionic-frameworkionic3

解决方案


您必须在其中填充一些值之前初始化crops和的所有属性。contracts因为,我不知道crops. 我无法展示如何初始化所有数组属性。但是对于普通数组,下面的初始化将起作用。

this.crops = [];
this.contracts = [];

因此,您的代码将如下所示:

...
console.log("Into the stats page........");
console.log("cropProvider: " + cropProvider);
console.log("contractProvider: " + contractProvider);

this.crops = [];
this.contracts = [];

this.cropProvider.getAllCrops()
  .then((crops: Crop[]) => {
    this.crops = crops;
  })
  .catch(e => console.error(e));
...

仅供参考:在构造函数中有业务逻辑是不好的。


推荐阅读