Труба '' не найдена angular2 custom pipe


105

Кажется, я не могу исправить эту ошибку. У меня есть панель поиска и 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"

1
Вы включили это в каналы компонента?
Гарри Нинь

Я просто понял, что это было причиной. Почему пример angular для кастомной
Sumama Waheed

Они определили это как глобальную трубу. Вы можете сделать то же самое со своим пользовательским каналом, если вы используете его во многих местах и ​​не хотите определять его в каждой аннотации.
Гарри Нинь

@SumamaWaheed Я почти уверен, что это было в какой-то момент в документации, но вы правы, документы теперь не упоминают / не показывают это.
Микеланджело

Ответы:


144

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

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

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

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

Модуль трубы

 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()
    ....
  ],

6
Это решение было единственным, что сработало для меня. Оказывается, для модуля необходимы трубы
AJ Zane

Я тоже обнаружил, что это частично решает мою ошибку "канал не найден" в Ng 2.8. * Кроме того, у меня были "предупреждения" машинописного текста, связанные только с используемыми соглашениями об именах, которые после их решения способствовали правильной транспиляции этого пользовательского канала и, в конечном итоге, его обнаружению в шаблоне.
CNSKnight,

Это действительно единственное решение, которое сработало для меня! Я попробовал использовать весь общий модуль, но это решение отлично сработало. Спасибо, @Karl!
lulu88

как мы протестируем это в нашем компонентном тесте,
апурва

2
Спасибо! Моя проблема заключалась в том, что я пропустил «экспорт: [myPipe]», думая, что экспорт предназначен только для модулей!
Рафик Мохаммед

55

Вам необходимо включить свой канал в объявление модуля:

declarations: [ UsersPipe ],
providers: [UsersPipe]

5
Замечу, что изначально я просто включил канал в провайдеры. Это необходимо включить как в объявления, так и в поставщики файла модуля.
Greg A

Я боролся, пока не последовал твоему предложению. Я потратил около 4 часов, чтобы просто понять это. Спасибо за предложение.
user1501382

5
Почему это не задокументировано? В документации указано You must include your pipe in the declarations array of the AppModule.: angular.io/guide/pipes . Во всяком случае, ваш ответ также решает мою проблему.
Martijn

Спасибо, Ювальс. Добавляю деталь: объявление модуля, в котором нужна труба.
Винисиос Торрес

5
Не забудьте также указать, будет exports: [UsersPipe]ли модуль импортирован другими модулями.
Precastic

18

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

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

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

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

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>


Это была палочка-выручалочка для ionic, спасибо. Поскольку "ionic generate pipe ...." не генерирует всех необходимых шагов, таких как создание pipe.module.ts. Ваш подход отлично сработал. Обратите внимание, что для ionic v4 необходимо внести небольшие изменения в пути импорта.
royappa 02

1
Я обнаружил, что вам не нужен импорт в app.module.ts, поэтому этот шаг можно пропустить. Это должно быть потому, что «общий модуль» в любом случае импортируется в другой модуль, где он необходим. Было бы неплохо, если бы импорт app.module работал глобально, но я пробовал, и это не так.
royappa 02

Я все еще сталкиваюсь с этим: Файл ОШИБКИ КОНСОЛИ: node_modules/@angular/core/fesm5/core.js: 4002: 0 Ошибка ОШИБКИ: Не перехвачено (в обещании): NullInjectorError: StaticInjectorError (AppModule) [ToHtmlPipe -> DomSanitizer]: StaticInjectorError (Платформа: ядро) [ToHtmlPipe -> DomSanitizer]: NullInjectorError: Нет провайдера для DomSanitizer!
mircobabini

13

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

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

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

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


2
Спасибо, что добавили это. У меня это сработало только после того, как было добавлено в Sub-SharedModule
jmcgrath207,

Да, то же самое здесь, часть, которую мне не хватало, - это импорт PipesModule в Sub-SharedModule.
вырезка

1

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

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

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

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

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

Но одна труба не может быть частью двух модулей .... Вышеупомянутый подход делает ее более доступной в разных модулях.
Himanshu Bansal

0

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

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

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

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

1
В Plunker, который вы разместили выше, каналы импортируются в модуль приложения (точно так же, как вы это делаете с самими компонентами), что делает канал доступным для всех компонентов в этом модуле.
ABabin

О, хорошо, я действительно смотрел на компонент, который на самом деле использует настраиваемый канал. Я не знал, что его можно импортировать глобально в модуль приложения. Спасибо
Сумама Вахид

пользователи-filter.pipe? почему .pipe?
Натер Уэббер,

1
Это просто соглашение об именах, файл называется users-filter.pipe.ts
Сумама Вахид

2
@SachinThampan может быть потому, что это было, когда angular был в rc5, я думаю ... с тех пор все изменилось, особенно с NgModule. Пожалуйста, посмотрите документацию для NgModule
Sumama Waheed

-1
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.

-2

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

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()
    ....
  ],

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.