La tubería '' no se pudo encontrar la tubería personalizada angular2

105

Parece que no puedo corregir este error. Tengo una barra de búsqueda y un ngFor. Estoy tratando de filtrar la matriz usando una tubería personalizada como esta:

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);
  }
}

Uso:

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

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

Error:

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)">

Versiones angulares:

"@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"
Sumama Waheed
fuente
1
¿Lo incluyó en las tuberías del componente?
Harry Ninh
Me acabo de dar cuenta de que esa era la razón. ¿Cómo es que el ejemplo angular para tubería personalizada nunca hace esto? Angular.io/resources/live-examples/pipes/ts/plnkr.html
Sumama Waheed
Lo definieron como tubería global. Puede hacer lo mismo con su tubería personalizada si la usa en muchos lugares y no desea definirla en cada anotación.
Harry Ninh
@SumamaWaheed Estoy bastante seguro de que estuvo allí en algún momento en los documentos, pero está en lo correcto, los documentos ahora no lo mencionan / muestran.
Michelangelo

Respuestas:

144

Asegúrese de no enfrentarse a un problema de "módulo cruzado"

Si el componente que está usando la tubería no pertenece al módulo que ha declarado el componente de tubería "globalmente", entonces la tubería no se encuentra y aparece este mensaje de error.

En mi caso, he declarado la tubería en un módulo separado e importé este módulo de tubería en cualquier otro módulo que tenga componentes que usen la tubería.

He declarado que el componente en el que está utilizando la tubería es

el módulo de tubería

 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: [],
      };
   }
 } 

Uso en otro módulo (por ejemplo, módulo de aplicación)

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

  @NgModule({
     imports: [
    ...
    , PipeModule.forRoot()
    ....
  ],
Karl
fuente
6
Esta solución fue la única que funcionó para mí. Resulta que las tuberías deben tener un módulo
AJ Zane
Yo también encontré que esto solucionaba parcialmente mi error de tubería no encontrada en Ng 2.8. * Además, tenía "advertencias" mecanografiadas relacionadas solo con las convenciones de nomenclatura en uso, que al resolverlas, contribuyeron a que esta tubería personalizada se transpilara correctamente y finalmente se encontrara en la plantilla.
CNSKnight
¡Esta es realmente la única solución que funcionó para mí! Probé todo el módulo compartido, pero esta solución funcionó como un encanto. ¡Gracias @Karl!
lulu88
¿Cómo probamos esto en nuestra prueba de componentes?
apoorva
2
¡Gracias! Mi problema fue que me perdí "exportaciones: [myPipe]" pensando que las exportaciones son solo para módulos.
Rafique Mohammed
55

Debe incluir su tubería en la declaración del módulo:

declarations: [ UsersPipe ],
providers: [UsersPipe]
Yuvals
fuente
5
Solo una nota, originalmente solo incluí la tubería en los proveedores. Esto debe incluirse tanto en las declaraciones como en los proveedores del archivo del módulo.
Greg A
Estuve luchando hasta que seguí tu sugerencia. Perdí alrededor de 4 horas para resolverlo. Gracias por la sugerencia.
user1501382
5
¿Por qué no está esto documentado? La documentación dice You must include your pipe in the declarations array of the AppModule.: angular.io/guide/pipes . De todos modos, tu respuesta también soluciona mi problema.
Martijn
Gracias, Yuvals. Añado un detalle: declaración del módulo donde necesitas la tubería.
Vinicios Torres
5
No olvide incluir también exports: [UsersPipe]si el módulo será importado por otros módulos.
Precastic
18

Para Ionic, puede enfrentar múltiples problemas como mencionó @Karl. La solución que funciona perfectamente para páginas cargadas diferidas iónicas es:

  1. Cree un directorio de tuberías con los siguientes archivos: pipe.ts y pipe.module.ts

// pipe.ts contenido (puede tener múltiples tuberías en su interior, solo recuerde

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;
  }
}

// contenido de las tuberías.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. Incluya PipesModule en app.module y en la sección de importaciones de @NgModule

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

  2. Incluya PipesModule en cada uno de sus .module.ts donde desee utilizar tuberías personalizadas. No olvide agregarlo a la sección de importaciones. // Ejemplo. archivo: pages / my-custom-page / my-custom-page.module.ts

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

  3. Eso es. Ahora puede usar su tubería personalizada en su plantilla. Ex.

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

Timoteo
fuente
Este fue un salvavidas para ionic, gracias. Porque "ionic generate pipe ..." no genera todos los pasos necesarios, como crear el pipe.module.ts. Tu enfoque funcionó a la perfección. Tenga en cuenta que para ionic v4, se necesitan algunos pequeños cambios en las rutas de importación.
royappa
1
Descubrí que no necesita las importaciones en app.module.ts, por lo que ese paso se puede omitir. Debe ser porque el "módulo compartido" se está importando de todos modos en cada otro módulo donde se necesita. Sería bueno si la importación de app.module funcionara globalmente, pero lo intenté y no funciona.
royappa
Todavía estoy enfrentando esto: CONSOLE ERROR file: node_modules/@angular/core/fesm5/core.js: 4002: 0 ERROR Error: Uncaught (in promise): NullInjectorError: StaticInjectorError (AppModule) [ToHtmlPipe -> DomSanitizer]: StaticInjectorError (Plataforma: núcleo) [ToHtmlPipe -> DomSanitizer]: NullInjectorError: ¡No hay proveedor para DomSanitizer!
mircobabini
12

Encontré la respuesta del "módulo cruzado" anterior muy útil para mi situación, pero me gustaría ampliar eso, ya que hay otra arruga a considerar. Si tiene un submódulo, tampoco puede ver las tuberías en el módulo principal en mis pruebas. También por esa razón, es posible que deba colocar tuberías en su propio módulo separado.

Aquí hay un resumen de los pasos que tomé para abordar las tuberías que no están visibles en el submódulo:

  1. Saque las tuberías de SharedModule (principal) y colóquelas en PipeModule
  2. En SharedModule, importe PipeModule y exporte (para otras partes de la aplicación que dependen de SharedModule para obtener acceso automáticamente a PipeModule)
  3. Para Sub-SharedModule, importe PipeModule, para que pueda obtener acceso a PipeModule, sin tener que volver a importar SharedModule, lo que crearía un problema de dependencia circular, entre otros problemas.

Otra nota al pie de la respuesta de "módulo cruzado" anterior: cuando creé el PipeModule, eliminé el método estático forRoot e importé PipeModule sin eso en mi módulo compartido. Mi conocimiento básico es que forRoot es útil para escenarios como singletons, que no se aplican necesariamente a los filtros.

sarora
fuente
1
Gracias por agregar esto. Solo funcionó para mí una vez que se agregó a Sub-SharedModule
jmcgrath207
Sí, lo mismo aquí, la parte que me faltaba era importar PipesModule al Sub-SharedModule.
lomo
1

Sugerir una respuesta alternativa aquí:

No se requiere hacer un módulo separado para la tubería , pero definitivamente es una alternativa. Consulte la nota al pie de la documentación oficial: https://angular.io/guide/pipes#custom-pipes

Utiliza su tubería personalizada de la misma manera que usa las tuberías integradas.
Debe incluir su tubería en la matriz de declaraciones del AppModule. Si elige inyectar su tubería en una clase, debe proporcionarla en la matriz de proveedores de su NgModule.

Todo lo que tiene que hacer es agregar su tubería a la matriz de declaraciones y la matriz de proveedores en el lugar moduledonde desea usar la tubería.

declarations: [
...
CustomPipe,
...
],
providers: [
...
CustomPipe,
...
]
ykadaru
fuente
Pero una sola tubería no puede ser parte de 2 módulos ... El enfoque anterior lo hace más accesible en diferentes módulos.
Himanshu Bansal
0

Nota: solo si no está utilizando módulos angulares

Por alguna razón, esto no está en los documentos, pero tuve que importar la tubería personalizada en el componente

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

@Component({
    ...
    pipes:      [UsersPipe]
})
Sumama Waheed
fuente
1
En el Plunker que publicó anteriormente, las tuberías se importan en el módulo de la aplicación (exactamente como lo hace con los componentes en sí), lo que hace que la tubería esté disponible para todos los componentes de ese módulo.
ABabin
Oh, está bien, en realidad estaba mirando el componente que realmente usa la tubería personalizada. No sabía que se podía importar globalmente en el módulo de la aplicación. Gracias
Sumama Waheed
users-filter.pipe? ¿por qué .pipe?
Nather Webber
1
Eso es solo una convención de nomenclatura, el archivo se llama users-filter.pipe.ts
Sumama Waheed
2
@SachinThampan podría ser porque esto era cuando angular estaba en rc5, creo ... las cosas cambiaron desde entonces, especialmente con NgModule. Consulte los documentos de 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.
Chowdeswara Rao
fuente
-2

He creado un módulo para tuberías en el mismo directorio donde están presentes mis tuberías

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

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

    export class SharedPipeModule { }   

Ahora importe ese módulo en app.module:

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

Ahora se puede usar importando el mismo en el módulo anidado

Amit Saini
fuente