Труба ' ' не может быть найдена angular2 custom pipe

Я не могу исправить эту ошибку. У меня есть панель поиска и ngFor. Я пытаюсь отфильтровать массив с помощью пользовательского канала, как это:

import { Pipe, PipeTransform } from '@angular/core';

import { User } from '../user/user';

@Pipe({
  name: 'usersPipe',
  pure: false
})
export class UsersPipe implements PipeTransform {
  transform(users: User [], searchTerm: string) {
    return users.filter(user => user.name.indexOf(searchTerm) !== -1);
  }
}

Использование:

<input [(ngModel)]="searchTerm" type="text" placeholder="Search users">

<div *ngFor="let user of (users | usersPipe:searchTerm)">
...
</div>

Ошибка:

zone.js:478 Unhandled Promise rejection: Template parse errors:
The pipe 'usersPipe' could not be found ("
<div class="row">
    <div  
    [ERROR ->]*ngFor="let user of (user | usersPipe:searchTerm)">

Угловые версии:

"@angular/common": "2.0.0-rc.5",
"@angular/compiler": "2.0.0-rc.5",
"@angular/core": "2.0.0-rc.5",
"@angular/platform-browser": "2.0.0-rc.5",
"@angular/platform-browser-dynamic": "2.0.0-rc.5",
"@angular/router": "3.0.0-rc.1",
"@angular/forms": "0.3.0",
"@angular/http": "2.0.0-rc.5",
"es6-shim": "^0.35.0",
"reflect-metadata": "0.1.3",
"rxjs": "5.0.0-beta.6",
"systemjs": "0.19.26",
"bootstrap": "^3.3.6",
"zone.js": "^0.6.12"

11 ответов

Решение

Убедитесь, что вы не столкнулись с проблемой "кросс-модуль"

Если компонент, который использует канал, не принадлежит модулю, который объявил компонент канала "глобально", то канал не найден, и вы получаете это сообщение об ошибке.

В моем случае я объявил трубу в отдельном модуле и импортировал этот модуль трубы в любой другой модуль, имеющий компоненты, использующие трубу.

Я объявил, что компонент, в котором вы используете канал

трубный модуль

 import { NgModule }      from '@angular/core';
 import { myDateFormat }          from '../directives/myDateFormat';

 @NgModule({
     imports:        [],
     declarations:   [myDateFormat],
     exports:        [myDateFormat],
 })

 export class PipeModule {

   static forRoot() {
      return {
          ngModule: PipeModule,
          providers: [],
      };
   }
 } 

Использование в другом модуле (например, app.module)

  // Import APPLICATION MODULES
  ...
  import { PipeModule }    from './tools/PipeModule';

  @NgModule({
     imports: [
    ...
    , PipeModule.forRoot()
    ....
  ],

Вы должны включить свою трубу в объявление модуля:

declarations: [ UsersPipe ],
providers: [UsersPipe]

Для Ionic вы можете столкнуться с несколькими проблемами, как упомянул @Karl. Решение, которое работает безупречно для ионных ленивых загруженных страниц:

  1. Создайте каталог для каналов со следующими файлами: pipe.ts и pipe.module.ts

// pipe.ts content (внутри может быть несколько каналов, просто не забудьте

use @Pipe function before each class)
import { PipeTransform, Pipe } from "@angular/core";
@Pipe({ name: "toArray" })
export class toArrayPipe implements PipeTransform {
  transform(value, args: string[]): any {
    if (!value) return value;
    let keys = [];
    for (let key in value) {
      keys.push({ key: key, value: value[key] });
    }
    return keys;
  }
}

// pipe.module.ts content

import { NgModule } from "@angular/core";
import { IonicModule } from "ionic-angular";
import { toArrayPipe } from "./pipes";

@NgModule({
  declarations: [toArrayPipe],
  imports: [IonicModule],
  exports: [toArrayPipe]
})
export class PipesModule {}
  1. Включите PipesModule в раздел импорта app.module и @NgModule.

    import { PipesModule } from "../pipes/pipes.module"; @NgModule({ imports: [ PipesModule ] });

  2. Включите PipesModule в каждый из ваших.module.ts, где вы хотите использовать пользовательские каналы. Не забудьте добавить его в раздел импорта. // Пример. файл: pages / my-custom-page / my-custom-page.module.ts

    import { PipesModule } from "../../pipes/pipes.module"; @NgModule({ imports: [ PipesModule ] })

  3. Это оно. Теперь вы можете использовать свой собственный канал в своем шаблоне. Ex.

<div *ngFor="let prop of myObject | toArray">{{ prop.key }}</div>

Я нашел ответ "перекрестный модуль" выше очень полезным для моей ситуации, но хотел бы остановиться на этом, так как есть еще одна проблема, которую нужно рассмотреть. Если у вас есть подмодуль, он также не может видеть каналы в родительском модуле в моем тестировании. По этой же причине вам может потребоваться поместить трубы в отдельный модуль.

Вот краткое изложение шагов, которые я предпринял для адресации каналов, не видимых в подмодуле:

  1. Возьмите трубы из (родительского) SharedModule и поместите в PipeModule
  2. В SharedModule импортируйте PipeModule и экспортируйте (для других частей приложения, зависящих от SharedModule, для автоматического получения доступа к PipeModule)
  3. Для Sub-SharedModule импортируйте PipeModule, чтобы он мог получить доступ к PipeModule, без необходимости повторно импортировать SharedModule, что могло бы вызвать проблему циклической зависимости, среди других проблем.

Еще одна сноска к приведенному выше ответу "кросс-модуль": когда я создавал PipeModule, я удалил статический метод forRoot и импортировал PipeModule без него в свой общий модуль. Я понимаю, что forRoot полезен для таких сценариев, как синглтоны, которые не обязательно применяются к фильтрам.

Предлагая альтернативный ответ здесь:

Создание отдельного модуля для трубы не требуется, но, безусловно, является альтернативой. Проверьте официальную сноску документации: https://angular.io/guide/pipes

Вы используете свою собственную трубу так же, как вы используете встроенные трубы.
Вы должны включить свой канал в массив деклараций AppModule. Если вы решите внедрить свой канал в класс, вы должны предоставить его в массиве провайдеров вашего NgModule.

Все, что вам нужно сделать, это добавить свой канал в массив декларации, а массив провайдеров в module где вы хотите использовать трубу.

declarations: [
...
CustomPipe,
...
],
providers: [
...
CustomPipe,
...
]

Примечание: только если вы не используете угловые модули

По какой-то причине этого нет в документации, но мне пришлось импортировать пользовательский канал в компонент

import {UsersPipe} from './users-filter.pipe'

@Component({
    ...
    pipes:      [UsersPipe]
})

Пользовательские каналы: когда создается пользовательский канал, он должен быть зарегистрирован в используемом модуле и компоненте.

      export class SummaryPipe implements PipeTransform{
//Implementing transform

  transform(value: string, limit?: number): any { 
    if (!value) {
        return null;
    }
    else {
        let actualLimit=limit>0?limit:50
       return value.substr(0,actualLimit)+'...'
    } 
  }
}

Добавить декоратор труб

       @Pipe({
        name:'summary'
    })

и обратитесь

      import { SummaryPipe } from '../summary.pipe';` //**In Component and Module**
      <div>
    **{{text | summary}}**  //Name should same as it is mentioned in the decorator.
</div>

//summary - это имя, объявленное в декораторе Pipe

Если вы видите эту ошибку при запуске тестов, убедитесь, что вы импортировали модуль, которому принадлежит канал, например:

    beforeEach(async(() => {
        TestBed.configureTestingModule({
            imports: [CustomPipeModule],
            declarations: [...],
            providers: [...],
            ...
        }).compileComponents();
    }));

Я столкнулся с той же проблемой.

Первоначально это было a "cross module" problemкак описано здесь

Но это еще не все.

Запуск приложения в течение длительного времени - приложение не смогло разобраться с этим новым импортированным каналом.

я перезапускаю ng serveкоманда - и наконец cross moduleушел

import { Component, Pipe, PipeTransform } from '@angular/core';

@Pipe({
  name: 'timePipe'
})
export class TimeValuePipe implements PipeTransform {

  transform(value: any, args?: any): any {
   var hoursMinutes = value.split(/[.:]/);
  var hours = parseInt(hoursMinutes[0], 10);
  var minutes = hoursMinutes[1] ? parseInt(hoursMinutes[1], 10) : 0;
  console.log('hours ', hours);
  console.log('minutes ', minutes/60);
  return (hours + minutes / 60).toFixed(2);
  }
}
@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  name = 'Angular';
  order = [
    {
      "order_status": "Still at Shop",
      "order_id": "0:02"
    },
    {
      "order_status": "On the way",
      "order_id": "02:29"
    },
    {
      "order_status": "Delivered",
      "order_id": "16:14"
    },
     {
      "order_status": "Delivered",
      "order_id": "07:30"
    }
  ]
}

Invoke this module in App.Module.ts file.

Я создал модуль для каналов в том же каталоге, где присутствуют мои каналы

import { NgModule } from '@angular/core';
///import pipe...
import { Base64ToImage, TruncateString} from './'  

   @NgModule({
        imports: [],
        declarations: [Base64ToImage, TruncateString],
        exports: [Base64ToImage, TruncateString]
    })

    export class SharedPipeModule { }   

Теперь импортируйте этот модуль в app.module:

import {SharedPipeModule} from './pipe/shared.pipe.module'
 @NgModule({
     imports: [
    ...
    , PipeModule.forRoot()
    ....
  ],

Теперь его можно использовать, импортировав его во вложенный модуль.

Другие вопросы по тегам