How to access properties of uninitialized componen

2019-07-26 23:39发布

问题:

I can't figure out how to access properties of a component in Angular using Ionic Framework Tutorial template. It seems to be uninitialized, because I tried to print it out to the console. Here is the code in app.component.ts:

export class MyApp {
  @ViewChild(Nav) nav: Nav;

  pages: Array<{title: string, badge: number, component: any}>;

  constructor(
    public platform: Platform,
    public menu: MenuController,
    public statusBar: StatusBar,
    public splashScreen: SplashScreen,
    public authService: AuthService,
    public loadingCtrl: LoadingController,
    private toastCtrl: ToastController
  ) {
   this.initializeApp();

   // set our app's pages
   this.pages = [
     { title: 'Series', badge: 0, component: SeriesDetailPage },
     { title: 'Borrow', badge: 0, component: BorrowViewPage },
     { title: 'Request', badge: 0, component: RequestViewPage },
     { title: 'Borrow List', badge: 0, component: BorrowListPage },
     { title: 'Request List', badge: 0, component: RequestListPage },
     { title: 'Setting', badge: 0, component: SettingPage }
   ];

   var borrowPage = this.pages.find(page => page.title === 'Borrow');
   console.log((borrowPage.component as BorrowViewPage).items); //Print undefined
   this.nav.setRoot(BorrowViewPage);
  }
  ...
  openPage(page) {
    // close the menu when clicking a link from the menu
    this.menu.close();
    // navigate to the new page if it is not the current page
    this.nav.setRoot(page.component);
  }

Here is the code for BorrowViewPage component:

export class BorrowViewPage {
  public items: Borrow[];

  constructor(public navCtrl: NavController, public authService: AuthService, public navParams: NavParams) {
    this.view(); //Make a HTTP call to initialize items array
  }
}

It seems that none of the components have its constructor called at this point. If so, is it possible to call the component constructor manually?

ADDED: What magical is that I don't know where the class instance even comes from. Here is where the app starts at app.module.ts:

@NgModule({
  declarations: [
    MyApp,
    SettingPage,
    SeriesDetailPage,
    SeriesListPage,
    BorrowListPage,
    BorrowViewPage,
    RequestListPage,
    RequestViewPage
  ],
  imports: [
    BrowserModule,
    HttpModule,
    IonicModule.forRoot(MyApp),
  ],
  bootstrap: [IonicApp],
  entryComponents: [
    MyApp,
    SettingPage,
    SeriesDetailPage,
    SeriesListPage,
    BorrowListPage,
    BorrowViewPage,
    RequestListPage,
    RequestViewPage
  ],
  providers: [
    StatusBar,
    SplashScreen,
    {provide: ErrorHandler, useClass: IonicErrorHandler},
    AuthService
  ]
})
export class AppModule {}

By setting the root page to any page you want in app.component.ts, the constructor of that component name get called. I think the constructor is called then?! Not sure. It works in the same way when I click on any of the buttons specified in app.html:

<ion-menu [content]="content">

  <ion-header>
    <ion-toolbar>
      <ion-title>MyApp</ion-title>
    </ion-toolbar>
  </ion-header>

  <ion-content>
    <ion-list>
      <button ion-item *ngFor="let p of pages" (click)="openPage(p)">
        {{p.title}}
        <ng-container *ngIf="p.badge != 0">
            <span class="badge badge-assertive">{{p.badge}}</span>
        </ng-container>
      </button>
    </ion-list>
  </ion-content>
</ion-menu>

<ion-nav [root]="rootPage" #content swipeBackEnabled="false"></ion-nav>

How do I even retrieve that class instance in this case?

回答1:

Updating my answer here as I realized I just jumped into conclusion (that because you have async call the data is not yet available and hence result is 'undefined').

Now as I looked closer I realize that what you are trying to do (access child's component (BorrowViewPage) data/property from parent scope (MyApp)) is not conventional and is not how Angular wants you to do it: https://angular.io/guide/component-interaction#component-interaction

I think in your use case you should consider this interaction model:https://angular.io/guide/component-interaction#parent-and-children-communicate-via-a-service

Rationale here is that in your case both components (MyApp and BorrowViewPage) require to access same data which ideally should be available at a "foundation" or "shared" service.

Service should be initialized and imported/injected into each of the components and this way you are getting cleaner design:

It is also a better practice to move your http calls to a provider and have components call / subscribe to them. So I think you can get cleaner implementation this way.

If you have a reason why you still want to achieve something with your current approach and that the canonical approach (shared service) is not suitable - please share those reasons.