为ionic app创建一个公共头元素会在--prod build中引发错误

时间:2017-11-22 07:44:00

标签: angular cordova ionic-framework ionic2 ionic3

我一直在研究一个离子3应用程序,它有一些带有公共标题的页面,只有标题内部元素的一些细微差别。为了避免代码重复并保持自己DRY,我尝试为此标题创建一个可重用的组件,并将其包含在所需的每个页面中。

在这个组件中,我有几个属性,我用它来通过属性绑定来控制元素的差异。在开发构建中一切正常。但是今天当我尝试创建--prod构建时,它会向我显示以下错误。

Error: Template parse errors:
Can't bind to 'isHome' since it isn't a known property of 'ion-header'.
1. If 'ion-header' is an Angular component and it has 'isHome' input, then verify that it is part of this module.
2. If 'ion-header' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message.
3. To allow any property add 'NO_ERRORS_SCHEMA' to the '@NgModule.schemas' of this component. ("
  Ionic pages and navigation.
-->
<ion-header clean-header [ERROR ->][isHome]="true" (refresh)="refresh($event);"></ion-header>

我将附上下面的代码,单个文件,我理解这是一个问题,因为我对angular4 / ionic3的依赖注入和模板绑定结构的误解。但我无法理解给定的错误,我尝试了错误本身中列出的3个解决方案,但我仍然遗漏了一些错误并保持不变。

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { ErrorHandler, NgModule } from '@angular/core';
import { IonicApp, IonicErrorHandler, IonicModule } from 'ionic-angular';
import { SplashScreen } from '@ionic-native/splash-screen';
import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { HttpClientModule } from '@angular/common/http';
import { StatusBar } from '@ionic-native/status-bar';
import { LaunchNavigator} from '@ionic-native/launch-navigator';

import { MyApp } from './app.component';
import { Header } from '../pages/header/header';
import { HomePage } from '../pages/home/home';
import {AssignmentDetailPage} from '../pages/assignment-detail/assignment-detail';
import { LoginPage } from '../pages/login/login';
import {ReportIssuePage} from '../pages/report-issue/report-issue';
import { AuthServiceProvider } from '../providers/auth-service/auth-service';
import { BaseUrl, Base } from './config/config.constants';
import { LoadingInterceptor } from '../interceptors/loading.interceptor';
import { DataStoreProvider } from '../providers/data-store/data-store';
import { HomeServiceProvider } from '../providers/home-service/home-service';
import { SessionInterceptor } from '../interceptors/session.interceptor';
import { AssignmentStatusProvider } from '../providers/assignment-status/assignment-status';
import { Camera } from '@ionic-native/camera';
import { File} from '@ionic-native/file';


@NgModule({
  declarations: [
    MyApp,
    HomePage,
    LoginPage,
    Header,
    AssignmentDetailPage,
    ReportIssuePage
  ],
  imports: [
    BrowserModule,
    HttpClientModule,
    IonicModule.forRoot(MyApp, {
      mode : 'md',
    })
  ],
  bootstrap: [IonicApp],
  entryComponents: [
    MyApp,
    HomePage,
    LoginPage,
    AssignmentDetailPage,
    ReportIssuePage
  ],
  providers: [
    StatusBar,
    SplashScreen,
    {provide: ErrorHandler, useClass: IonicErrorHandler},
    {provide:Base, useValue:BaseUrl},
    {provide: HTTP_INTERCEPTORS, useClass: LoadingInterceptor, multi:true},
    {provide: HTTP_INTERCEPTORS, useClass: SessionInterceptor, multi:true},
    AuthServiceProvider,
    DataStoreProvider,
    Camera,
    File,
    HomeServiceProvider,
    AssignmentStatusProvider,
    LaunchNavigator,
  ]
})
export class AppModule {}

header.module.ts

import { NgModule } from '@angular/core';
import { Header } from './header';

@NgModule({
  declarations: [
    Header,
  ],
  imports: [
  ],
  exports: [
    Header
  ]
})
export class HeaderModule {}

header.ts

import { Component, EventEmitter, Input, Output } from '@angular/core';
import { AuthServiceProvider } from '../../providers/auth-service/auth-service';
import { AlertController, NavController } from 'ionic-angular';
import { HomePage } from '../home/home';
import { LoginPage } from '../login/login';
import { HomeServiceProvider } from '../../providers/home-service/home-service';

@Component({
  selector: '[clean-header]',
  templateUrl: 'header.html',
})
export class Header {
  @Input() isHome: boolean = false;
  @Output() refresh: EventEmitter<any> = new EventEmitter();
  public user: any;
  constructor(public Auth: AuthServiceProvider, public nav: NavController,
     public alertCtrl: AlertController, public HomeService: HomeServiceProvider) {

    this.user = Auth.getUserData();
  }

了header.html

  <ion-navbar hideBackButton>
    <div text-center>
    <img class="header-logo" src="./assets/imgs/clean_connect.png" alt="Logo of clean connect">
    </div>
    <ion-grid>
      <ion-row>
        <ion-col col-8>
          <div class="name-section">
            <h4 class="header-username">{{user.userName | uppercase}}</h4>
            <p>{{user.firstName +', '+ user.lastName}}</p>
          </div>
        </ion-col>
        <ion-col col-4 class="nav-controls">
          <a (click)="refreshData()" *ngIf="isHome"><img src="./assets/imgs/ic_refresh.png"   alt="Logo of Refresh"></a>
          <a (click)="goHome();" *ngIf="!isHome"><img src="./assets/imgs/home.png"   alt="Logo of Home"></a>
          <a (click)="logout()"><img src="./assets/imgs/logout.png"   alt="Logo of Logout"></a>
        </ion-col>
        <ion-col col-2 class="nav-controls">

        </ion-col>
      </ion-row>
    </ion-grid>
  </ion-navbar>

最后我在其他地方使用这个组件,

home.html的

<ion-header clean-header [isHome]="true" (refresh)="refresh($event);"></ion-header>
<ion-content>

我尝试将它用作自定义元素而不是属性,但由于自定义元素位于ion-header和ion-content之间,因此无法生成所需的布局,我无法找到方法像angular1中的方式一样使用包含。

我知道这个问题很长,但我不能做一个工作小提琴。有谁可以帮助我?

2 个答案:

答案 0 :(得分:2)

注意:尽管有上述关于最佳实践的建议,但我在创建组件时遇到了类似的错误,因此为搜索错误的其他人提供了答案。 在我的情况下,我只有一个普通的旧组件,我有同样的错误,除了它抱怨离子标签。这第一次让我花了很多时间进行挖掘和反复试验。我发现文档的主题不太明确,或者我可能没有设法谷歌做正确的事。

您需要将IonicModule导入header.module.ts以及app.module.ts,即

import { NgModule } from '@angular/core';
import { IonicModule } from 'ionic-angular';
import { Header } from './header';

@NgModule({
  declarations: [
    Header,
  ],
  imports: [
    IonicModule      // <-- add here
  ],
  exports: [
    Header
  ]
})
export class HeaderModule {}

请注意,实时重新加载可能会在第一次错过此更改,因此请确保杀死并重新启动离子服务。

以下错误报告评论帮助我解决了这个问题: https://github.com/angular/angular/issues/14288#issuecomment-282531453 https://forum.ionicframework.com/t/ionic-3-0-shared-component/91727/2

答案 1 :(得分:1)

我找到了答案。

  

但根据离子团队的建议,明智的不是   由于离子,将公共标题放在每个页面上   内部设计决策。感谢sebaferreras的建议。我不建议任何人在不考虑费用的情况下做以下事情。但我想证明它是可能的。

但是我仍然想要实现它,因为我的离子头具有一些中级复杂功能,我无法在我使用的每一页上复制它们。我实现了如下,

1)从app.module.ts中删除对module / component.ts的任何引用,从app.module.ts中删除任何组件导入,

2)在标题(可重用)模块的导入部分导入IonicModule(header,module.ts)

import { NgModule } from '@angular/core';
import { Header } from './header';
import {IonicModule} from "ionic-angular";

@NgModule({
  declarations: [
    Header,
  ],
  imports: [
    IonicModule
  ],
  exports: [
    Header
  ]
})
export class HeaderModule {}

然后在每个其他页面的模块中导入HeaderModule,记住不要在component.ts文件中,而是在该文件的模块中。

home.module.ts

import { NgModule } from '@angular/core';
import { IonicPageModule } from 'ionic-angular';
import { HomePage } from './home';
import {HeaderModule} from "../header/header.module";

@NgModule({
  declarations: [
    HomePage,
  ],
  imports: [
    IonicPageModule.forChild(HomePage),
    HeaderModule,
  ],
  exports: [
    HomePage
  ]
})
export class HomePageModule {}

这可以按预期工作,我没有注意到任何副作用,对于那个动画部分,我们当前的项目并不关心动画标题,所以如果它没有工作它不是我的用例有问题。根据您的使用情况进行相应检查。