Ionic3 - 自定义组件中的模板解析错误

aid*_*yth 8 ionic-framework ionic3 angular

我一直致力于一个项目,以便最近加快Ionic3的所有变化.它主要基于Ionic-Team的演示会议应用程序.

我仍然试图倾斜角度/离子,我让大多数应用程序在ionic2中运行.共享components.module延迟加载搞砸了我一段时间.但现在我在自定义组件中使用Ionic的内置组件时遇到了问题.我正在尝试构建一个使用ion-card的自定义组件来显示通过@Input传递给它的信息.

它给出的错误:

Error: Template parse errors:
'ion-card-header' is not a known element:
1. If 'ion-card-header' is an Angular component, then verify that it is part of this module.
2. If 'ion-card-header' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message. ("
<ion-card>

[ERROR ->]<ion-card-header>
    <h3>{{ recipe.title }}</h3>
</ion-card-header>
"): ng:///ComponentsModule/RecipeCardComponent.html@3:2
'ion-card-content' is not a known element:
1. If 'ion-card-content' is an Angular component, then verify that it is part of this module.
2. If 'ion-card-content' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message. ("
</ion-card-header>

[ERROR ->]<ion-card-content>
    <p>{{ recipe.description }}</p>
</ion-card-content>
"): ng:///ComponentsModule/RecipeCardComponent.html@7:2
'ion-card' is not a known element:
1. If 'ion-card' is an Angular component, then verify that it is part of this module.
2. If 'ion-card' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message. ("
[ERROR ->]<ion-card>

<ion-card-header>
"): ng:///ComponentsModule/RecipeCardComponent.html@1:0
Run Code Online (Sandbox Code Playgroud)

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { ErrorHandler, NgModule } from '@angular/core';
import { IonicApp, IonicErrorHandler, IonicModule } from 'ionic-angular';
import { StatusBar } from '@ionic-native/status-bar';
import { SplashScreen } from '@ionic-native/splash-screen';
import { IonicStorageModule } from '@ionic/storage';
import { HttpModule } from '@angular/http';

import { UserDataProvider } from '../providers/user-data/user-data';
import { RecipeDataProvider } from '../providers/recipe-data/recipe-data';

import { ComponentsModule } from '../components/components.module';
import { PipesModule } from '../pipes/pipes.module';

import { MyApp } from './app.component';
import { IntroPage } from '../pages/intro/intro';
import { RecipeListPage } from '../pages/recipe-list/recipe-list';
import { FavoratesPage } from '../pages/favorates/favorates';
import { CookbooksPage } from '../pages/cookbooks/cookbooks';
import { QuickTimerPage } from '../pages/quick-timer/quick-timer';
import { ShoppingListPage } from '../pages/shopping-list/shopping-list';
import { SettingsPage } from '../pages/settings/settings';
import { AboutPage } from '../pages/about/about';
import { DatabaseProvider } from '../providers/database/database';
import { UtilitiesProvider } from '../providers/utilities/utilities';


@NgModule({
declarations: [
    MyApp,
    IntroPage,
    RecipeListPage,
    FavoratesPage,
    CookbooksPage,
    QuickTimerPage,
    ShoppingListPage,
    SettingsPage,
    AboutPage
],
imports: [
    BrowserModule,
    HttpModule,
    IonicModule.forRoot(MyApp, {}, {
    links: [
        { component: IntroPage, name: 'IntroPage', segment: 'intro' },
        { component: RecipeListPage, name: 'RecipeListPage', segment: 'recipe-list' },
        { component: FavoratesPage, name: 'FavoratesPage', segment: 'favorates' },
        { component: CookbooksPage, name: 'CookbooksPage', segment: 'cookbooks' },
        { component: QuickTimerPage, name: 'QuickTimerPage', segment: 'quick-timer' },
        { component: ShoppingListPage, name: 'ShoppingListPage', segment: 'shopping-list' },
        { component: SettingsPage, name: 'SettingsPage', segment: 'settings' },
        { component: AboutPage, name: 'AboutPage', segment: 'settings' },
    ]
    }),
    IonicStorageModule.forRoot({
    name: '__mise',
    driverOrder: ['indexeddb', 'websql', 'localstorage']
    }),
    ComponentsModule,
    PipesModule
],
bootstrap: [IonicApp],
entryComponents: [
    MyApp,
    IntroPage,
    RecipeListPage,
    FavoratesPage,
    CookbooksPage,
    QuickTimerPage,
    ShoppingListPage,
    SettingsPage,
    AboutPage
],
providers: [
    StatusBar,
    SplashScreen,
    {provide: ErrorHandler, useClass: IonicErrorHandler},
    UserDataProvider,
    RecipeDataProvider,
    DatabaseProvider,
    UtilitiesProvider
]
})
export class AppModule {}
Run Code Online (Sandbox Code Playgroud)

app.component.ts

import { Component, ViewChild } from '@angular/core';
import { Nav, Platform } from 'ionic-angular';
import { StatusBar } from '@ionic-native/status-bar';
import { SplashScreen } from '@ionic-native/splash-screen';

import { Storage } from '@ionic/storage';

import { UserDataProvider } from '../providers/user-data/user-data';
import { RecipeDataProvider } from '../providers/recipe-data/recipe-data';

import { IntroPage } from '../pages/intro/intro';
import { RecipeListPage } from '../pages/recipe-list/recipe-list';


export interface PageInterface {
title: string;
name: string;
component: any;
icon: string;
logsOut?: boolean;
index?: number;
tabName?: string;
tabComponent?: any;
}

@Component({
templateUrl: 'app.html'
})
export class MyApp {
@ViewChild(Nav) nav: Nav;

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

// List of pages that can be navigated to from the left menu
// the left menu only works after login
// the login page disables the left menu
appPages: PageInterface[] = [
    { title: 'intro', name: 'IntroPage', component: 'IntroPage', icon: 'help' },
    { title: 'Recipes', name: 'RecipeListPage', component: 'RecipeListPage', icon: 'list' },
    { title: 'Favorates', name: 'FavoratesPage', component: 'FavoratesPage', icon: 'star' },
    { title: 'Cookbooks', name: 'CookbooksPage', component: 'CookbooksPage', icon: 'folder' },
    { title: 'Quick timer', name: 'QuickTimerPage', component: 'QuickTimerPage', icon: 'help' },
    { title: 'Shopping list', name: 'ShoppingListPage', component: 'ShoppingListPage', icon: 'help' },
    { title: 'Settings', name: 'SettingsPage', component: 'SettingsPage', icon: 'help' },
    { title: 'About', name: 'AboutPage', component: 'AboutPage', icon: 'help' },
];

rootPage: any;

constructor(
    public platform: Platform, 
    public statusBar: StatusBar,
    public storage: Storage, 
    public splashScreen: SplashScreen,
    public userData: UserDataProvider,
    public recipeData: RecipeDataProvider
) {

    // Check if the user has already seen the tutorial
    this.storage.get('hasSeenTutorial')
    .then((hasSeenTutorial) => {
        if (hasSeenTutorial) {
        console.log('HasSeenTurorial = true');
        this.rootPage = RecipeListPage;
        } else {
        console.log('HasSeenTurorial = false');
        this.rootPage = IntroPage;
        }
        this.platformReady()
    });

    // load the recipe data
    this.recipeData.init();

}

openPage(page: PageInterface) {
    this.nav.setRoot(page.name);
}

openTutorial() {
    this.nav.setRoot(IntroPage);
}

listenToLoginEvents() {
    // this.events.subscribe('user:login', () => {
    //   this.enableMenu(true);
    // });

    // this.events.subscribe('user:signup', () => {
    //   this.enableMenu(true);
    // });

    // this.events.subscribe('user:logout', () => {
    //   this.enableMenu(false);
    // });
}

enableMenu(loggedIn: boolean) {
    // this.menu.enable(loggedIn, 'loggedInMenu');
    // this.menu.enable(!loggedIn, 'loggedOutMenu');
}

platformReady() {
    // Call any initial plugins when ready
    this.platform.ready().then(() => {
    this.splashScreen.hide();
    });
}

isActive(page: PageInterface) {
    let childNav = this.nav.getActiveChildNavs()[0];

    // Tabs are a special case because they have their own navigation
    if (childNav) {
    if (childNav.getSelected() && childNav.getSelected().root === page.tabComponent) {
        return 'primary';
    }
    return;
    }

    if (this.nav.getActive() && this.nav.getActive().name === page.name) {
    return 'primary';
    }
    return;
}
}
Run Code Online (Sandbox Code Playgroud)

偏方list.ts

import { Component } from '@angular/core';
import { IonicPage, NavController, NavParams } from 'ionic-angular';

import { RecipeDataProvider } from '../../providers/recipe-data/recipe-data';
import { UserDataProvider } from '../../providers/user-data/user-data';

import { ComponentsModule } from '../../components/components.module';


@IonicPage()
@Component({
    selector: 'page-recipe-list',
    templateUrl: 'recipe-list.html',
})
export class RecipeListPage {

    recipeList: any = [];
    things: any = ["One", "Two", "Three"];

    constructor(
        public navCtrl: NavController, 
        public navParams: NavParams,
        public recipeData: RecipeDataProvider,
        public userData: UserDataProvider
    ) {}

    goToRecipe(recipeId: any){

    };

    printRecipeList(){
        console.log(this.recipeList);
    }


    ionViewDidLoad() {
        console.log('ionViewDidLoad RecipeListPage');
        this.recipeList = this.recipeData.recipeList;
    }

}
Run Code Online (Sandbox Code Playgroud)

recipeList.html

<ion-header>
    <ion-navbar>
        <button ion-button menuToggle>
        <ion-icon name="menu"></ion-icon>
        </button>
        <ion-title>Recipe List</ion-title>
    </ion-navbar>
</ion-header>


<ion-content padding>
    <recipe-card *ngFor="let recipe of recipeList; let i = index" [recipe]="recipeList[i]"></recipe-card>
</ion-content>
Run Code Online (Sandbox Code Playgroud)

components.module.ts

import { NgModule } from '@angular/core';
import { RecipeCardComponent } from './recipe-card/recipe-card';
import { TimelineComponent } from './timeline/timeline';
import { TimerComponent } from './timer/timer';
@NgModule({
    declarations: [RecipeCardComponent,
    TimelineComponent,
    TimerComponent],
    imports: [],
    exports: [RecipeCardComponent,
    TimelineComponent,
    TimerComponent]
})
export class ComponentsModule {}
Run Code Online (Sandbox Code Playgroud)

偏方card.ts

import { Component, Input } from '@angular/core';
import { NavController, NavParams } from 'ionic-angular';
// Providers
import { UserDataProvider } from "../../providers/user-data/user-data";
import { RecipeDataProvider } from "../../providers/recipe-data/recipe-data";
// Model
import { Recipe } from "../../models/recipe-model";
// Pages
import { RecipeDetailPage } from "../../pages/recipe-detail/recipe-detail";


@Component({
    selector: 'recipe-card',
    templateUrl: 'recipe-card.html'
})
export class RecipeCardComponent {

    @Input() recipe: Recipe;

    constructor(
        public navCtrl: NavController,
        public navParams: NavParams,
        private userData: UserDataProvider,
        private recipeData: RecipeDataProvider
    ) {}

    delete(){
        console.log('dalete recipe');
        // this.recipeData.delete(this.recipe.recipeId);
    }

    goToRecipeDetailPage() {
        console.log('goToRecipe() recipe');
        this.navCtrl.push('RecipeDetailPage', this.recipe);
    }

}
Run Code Online (Sandbox Code Playgroud)

偏方card.html

<ion-card>

    <ion-card-header>
        <h3>{{ recipe.title }}</h3>
    </ion-card-header>

    <ion-card-content>
        <p>{{ recipe.description }}</p>
    </ion-card-content>

</ion-card>
Run Code Online (Sandbox Code Playgroud)

为了完整性这里是我的离子系统信息:

cli packages: (...)

    @ionic/cli-utils  : 1.12.0
    ionic (Ionic CLI) : 3.12.0

global packages:

    cordova (Cordova CLI) : 7.0.1

local packages:

    @ionic/app-scripts : 3.0.0
    Cordova Platforms  : none
    Ionic Framework    : ionic-angular 3.7.1

System:

    Node : v6.10.2
    npm  : 3.10.7
    OS   : Windows 10

Misc:

    backend : pro
Run Code Online (Sandbox Code Playgroud)

如果我使用以下代码的recipe-card.html它工作正常.

<h3>{{ recipe.title }}</h3>
<p>{{ recipe.description }}</p>
Run Code Online (Sandbox Code Playgroud)

但是,如果我包含以下代码,则会触发模板分析错误的离子图标.

<h3>{{ recipe.title }}</h3>

<p>{{ recipe.description }}</p>

<button ion-button icon-left>
    <ion-icon name="home"></ion-icon>
    Left Icon
</button>
Run Code Online (Sandbox Code Playgroud)

因此,在您自己的自定义组件中访问嵌套的离子内置组件似乎是出错的.对于延迟加载或共享components.module,这可能是明显的事情,但对于我的生活,我看不到它.任何帮助都会很棒:)提前谢谢.

aid*_*yth 19

回答我自己的问题:) |希望它能帮助别人.

要在您自己的自定义组件中使用Ionics内置组件,您需要将IonicModule导入component.module.ts并确保将IonicModule添加到@NgModule导入.这是一个之前/之后.

之前

import { NgModule } from '@angular/core';

import { RecipeCardComponent } from './recipe-card/recipe-card';
import { TimelineComponent } from './timeline/timeline';
import { TimerComponent } from './timer/timer';

@NgModule({
    declarations: [RecipeCardComponent,
    TimelineComponent,
    TimerComponent],
    imports: [],
    exports: [RecipeCardComponent,
    TimelineComponent,
    TimerComponent]
})
export class ComponentsModule {}
Run Code Online (Sandbox Code Playgroud)

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

import { RecipeCardComponent } from './recipe-card/recipe-card';
import { TimelineComponent } from './timeline/timeline';
import { TimerComponent } from './timer/timer';

@NgModule({
    declarations: [RecipeCardComponent,
    TimelineComponent,
    TimerComponent],
    imports: [IonicModule],
    exports: [RecipeCardComponent,
    TimelineComponent,
    TimerComponent]
})
export class ComponentsModule {}
Run Code Online (Sandbox Code Playgroud)


小智 8

**IonicModule**ComponentsModule没有forRoot()的情况下添加

imports: [IonicModule]
Run Code Online (Sandbox Code Playgroud)