NG0303:无法绑定到“ngIf”,因为它不是“[组件选择器]”的已知属性

问题描述 投票:0回答:2

我有一个页面 SearchPage,嵌套在项目根目录 HomePage 的主页面中,并且 SearchComponent 中有两个子组件:PromptComponentResultsComponent。这是

tree
输出:

src/app/home/
├── home.module.ts
├── home.page.html
├── home.page.scss
├── home.page.spec.ts
├── home.page.ts
├── home-routing.module.ts
└── search
    ├── prompt
    │   ├── prompt.component.html
    │   ├── prompt.component.scss
    │   ├── prompt.component.spec.ts
    │   └── prompt.component.ts
    ├── results
    │   ├── results.component.html
    │   ├── results.component.scss
    │   ├── results.component.spec.ts
    │   └── results.component.ts
    ├── search.module.ts
    ├── search.page.html
    ├── search.page.scss
    ├── search.page.spec.ts
    ├── search.page.ts
    └── search-routing.module.ts

如果我在主页中创建另一个带有路由(或组件,无关紧要)的页面,在地址栏中输入该路由,然后导航到

/search
,我会看到正确的内容,并且工作正常,没有错误。但是,如果我从那里刷新页面,或者在地址栏中输入
/search
,我会收到两个控制台错误:

NG0303: Can't bind to 'ngIf' since it isn't a known property of 'app-prompt'. core.js:10105
NG0303: Can't bind to 'ngIf' since it isn't a known property of 'app-results'. core.js:10105

这指的是 search.page.html 中的几个标签:

<app-prompt
  (queryEmitter)="update($event)"
  *ngIf="query === ''"
></app-prompt>
<app-results
  [query]="query"
  (queryEmitter)="update($event)"
  *ngIf="query !== ''"
></app-results>

当我看到错误时,这些组件不会被渲染。

当他们工作时,以下是他们如何工作。首先,

<app-prompt>
中会显示一个空提示。稍后,当用户在提示中键入某些内容时,
query
的值会从事件发射器传递到 SearchPage,然后再次传递到 ResultsComponent

其余代码如下。我怎样才能让它在每种情况下都起作用?

搜索.page.ts

import { Location } from '@angular/common';
import { Component, Input, OnInit } from '@angular/core';
import { ActivatedRoute, ParamMap } from '@angular/router';

/**
 * Main component for the search page and parent to `PromptComponent` and
 * `ResultsComponent`.
 *
 * @decorator `@Component({ selector: 'app-search', templateUrl: './search.page.html', styleUrls: ['./search.page.scss'], })`
 *
 * @alpha
 */
@Component({
  selector: 'app-search',
  templateUrl: './search.page.html',
  styleUrls: ['./search.page.scss'],
})
export class SearchPage implements OnInit {
  /**
   * Holds the value of `ion-searchbar` within each of the child components,
   * and allows for communication across components.
   *
   * @alpha
   */
  query!: string;

  /**
   * Constructor for the search page.
   *
   * @param _route `ActivatedRoute`
   * @param _location `Location`
   *
   * @alpha
   */
  constructor(private _route: ActivatedRoute, private _location: Location) {}

  /**
   * A lifecycle hook that is called after Angular has initialized all
   * data-bound properties of a directive. Takes query parameter from URL and
   * stores it locally.
   *
   * @alpha
   */
  ngOnInit(): void {
    this._route.paramMap.subscribe((paramMap: ParamMap) => {
      const query: null | string = paramMap.get('query');
      this.query = query ? query : '';
    });
  }

  /**
   * Method to update the `query` property and the URL.
   *
   * @param query String from search bar to be used in child components.
   *
   * @alpha
   */
  update(query: string): void {
    this.query = query;
    this._location.replaceState(`search${query ? '/' + query : ''}`);
  }
}

提示.组件.ts

import {
  AfterViewChecked,
  Component,
  EventEmitter,
  Output,
  ViewChild,
} from '@angular/core';
import { SearchbarChangeEventDetail } from '@ionic/core/dist/types/components/searchbar/searchbar-interface.d';

/**
 * Prompt component. Child component of Search page responsible for prompting
 * the user and indirectly passing data to its sibling component, Results, with
 * the help of Word page.
 *
 * @selector `@Component({ selector: 'app-prompt', templateUrl: './prompt.component.html', styleUrls: ['./prompt.component.scss'], })`
 *
 * @alpha
 */
@Component({
  selector: 'app-prompt',
  templateUrl: './prompt.component.html',
  styleUrls: ['./prompt.component.scss'],
})
export class PromptComponent implements AfterViewChecked {
  /**
   * Emitter object for passing query (text) value to the parent component for
   * its use and use by ResultsComponent.
   *
   * @alpha
   */
  @Output() queryEmitter = new EventEmitter<string>();

  /**
   * Reference to `ion-searchbar` element to be set to focus.
   *
   * @alpha
   */
  @ViewChild('searchbar') searchbar: HTMLIonInputElement;

  query:string;

  /**
   * Constructor that takes no arguments and does nothing.
   *
   * @alpha
   */
  constructor() {}

  /**
   * An Angular lifecycle hook that is called after the default change detector
   * has completed checking a component's view for changes. This method simply
   * calls setFocus() on the searchbar element.
   *
   * @alpha
   */
  ngAfterViewChecked(): void {
    this.searchbar.setFocus();
  }

  /**
   * Takes `ion-searchbar` value from template and emits it to the parent
   * component.
   *
   * @param $event The `ionChange` event object passed in via template.
   *
   * @alpha
   */
  onChange($event: CustomEvent<SearchbarChangeEventDetail>): void {
    this.queryEmitter.emit($event.detail.value);
  }
}

结果.component.ts

import {
  AfterViewChecked,
  Component,
  EventEmitter,
  Input,
  Output,
  ViewChild,
} from '@angular/core';
import { IonSearchbar } from '@ionic/angular';
import { SearchbarChangeEventDetail } from '@ionic/core/dist/types/components/searchbar/searchbar-interface.d';

/**
 * Results component. Child component of Search page responsible for taking in
 * user input and displaying search results. Currently, though, all it does is
 * take in input and switch to its sibling component, Prompt, when the input is
 * cleared.
 *
 * @selector `@Component({ selector: 'app-results', templateUrl: './results.component.html', styleUrls: ['./results.component.scss'], })`
 *
 * @alpha
 */
@Component({
  selector: 'app-results',
  templateUrl: './results.component.html',
  styleUrls: ['./results.component.scss'],
})
export class ResultsComponent implements AfterViewChecked {
  /**
   * Query text passed in from parent component, which receives it either from
   * the `:query` URL parameter or from `PromptComponent`.
   *
   * @alpha
   */
  @Input() query: string;

  /**
   * Emitter object for passing query (text) value to the parent component for
   * its use.
   *
   * @alpha
   */
  @Output() queryEmitter = new EventEmitter<string>();

  /**
   * Reference to `ion-searchbar` element to be set to focus.
   *
   * @alpha
   */
  @ViewChild('searchbar') searchbar: IonSearchbar;

  /**
   * Constructor that takes no arguments and does nothing apart from returning
   * the component instance.
   *
   * @alpha
   */
  constructor() {}

  /**
   * Ionic lifecycle hook that gets called when the component is about to enter
   * view. Here, the search results are updated.
   *
   * @alpha
   */
  ionViewWillEnter() {
    this.search();
  }

  /**
   * Angular lifecycle hook called after calls to ngAfterContentChecked() have
   * finished. This hook simply calls setFocus() on the searchbar element.
   *
   * @alpha
   */
  ngAfterViewChecked(): void {
    this.searchbar.setFocus();
  }

  /**
   * Takes `ion-searchbar` value from template and stores it locally. Then it
   * checks for an non-empty string, and if that passes, the search results are
   * updated. Finally, it emits the query value to the parent component, empty
   * or not.
   *
   * @param $event The `ionChange` event object passed in via template.
   *
   * @alpha
   */
  onChange($event: CustomEvent<SearchbarChangeEventDetail>): void {
    const query = $event.detail.value;
    this.query = query;

    if (query) {
      this.search();
    }

    this.queryEmitter.emit(query);
  }

  /**
   * Emits a blank query value to the parent component so focus is returned to
   * PromptComponent.
   *
   * @alpha
   */
  clear(): void {
    this.queryEmitter.emit('');
  }

  /**
   * Skeleton code for search functionality. Currently, it is used to log the
   * local value of `query` for debugging purposes.
   *
   * @alpha
   */
  private search(): void {
    console.log(this.query);
  }
}

编辑

app.module.ts

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { RouteReuseStrategy } from '@angular/router';

import { IonicModule, IonicRouteStrategy } from '@ionic/angular';

import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';
import { CommonModule } from '@angular/common';

@NgModule({
  declarations: [AppComponent],
  entryComponents: [],
  imports: [
    BrowserModule,
    IonicModule.forRoot(),
    AppRoutingModule,
    CommonModule,
  ],
  providers: [{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy }],
  bootstrap: [AppComponent],
})
export class AppModule {}

home.module.ts

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';

import { IonicModule } from '@ionic/angular';

import { HomePageRoutingModule } from './home-routing.module';

import { HomePage } from './home.page';

@NgModule({
  imports: [
    CommonModule,
    FormsModule,
    IonicModule,
    HomePageRoutingModule
  ],
  declarations: [HomePage]
})
export class HomePageModule {}

search.module.ts

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';

import { IonicModule } from '@ionic/angular';

import { SearchPageRoutingModule } from './search-routing.module';

import { SearchPage } from './search.page';
import { PromptComponent } from './prompt/prompt.component';
import { ResultsComponent } from './results/results.component';

@NgModule({
  imports: [
    CommonModule,
    FormsModule,
    IonicModule,
    SearchPageRoutingModule,
  ],
  declarations: [SearchPage, PromptComponent, ResultsComponent]
})
export class SearchPageModule {}

其他问题可以通过将

CommonModule
添加到 *.module.ts 来解决,但正如您在上面看到的,它已经包含在内。

angular ionic-framework
2个回答
2
投票

请转到您项目的正确 module.ts 文件并检查您是否已导入

CommonModule
.

否则,将其导入为

import { CommonModule } from '@angular/common';  

然后,将其添加到导入数组中。

 @NgModule({
    imports: [CommonModule],    // Import here
  ...
})
class YourModule {}

0
投票

在你的 component.ts 文件中

从'@angular/common'导入{CommonModule};

在@Component({ 选择器... 导入:[CommonModule], })

© www.soinside.com 2019 - 2024. All rights reserved.