Le tuyau «» n'a pas pu être trouvé tuyau personnalisé angular2

105

Je n'arrive pas à corriger cette erreur. J'ai une barre de recherche et un ngFor. J'essaie de filtrer le tableau en utilisant un tuyau personnalisé comme celui-ci:

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

Usage:

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

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

Erreur:

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

Versions angulaires:

"@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
la source
1
L'avez-vous inclus dans les tuyaux du composant?
Harry Ninh
Je viens de réaliser que c'était la raison. Comment se fait-il que l'exemple angulaire de tuyau personnalisé ne fasse jamais cela: angular.io/resources/live-examples/pipes/ts/plnkr.html
Sumama Waheed
Ils l'ont défini comme un tube global. Vous pouvez faire de même avec votre canalisation personnalisée si vous l'utilisez à de nombreux endroits et que vous ne souhaitez pas définir dans chaque annotation.
Harry Ninh
@SumamaWaheed Je suis à peu près sûr qu'il était là à un moment donné dans la documentation, mais vous avez raison, la documentation ne le mentionne / ne l'affiche pas.
Michelangelo

Réponses:

144

Assurez-vous que vous n'êtes pas confronté à un problème de "module croisé"

Si le composant qui utilise le tube n'appartient pas au module qui a déclaré le composant de tube "globalement", le tube n'est pas trouvé et vous obtenez ce message d'erreur.

Dans mon cas, j'ai déclaré le tube dans un module séparé et importé ce module de tube dans n'importe quel autre module ayant des composants utilisant le tube.

J'ai déclaré que le composant dans lequel vous utilisez le tuyau est

le module de canalisation

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

Utilisation dans un autre module (par exemple app.module)

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

  @NgModule({
     imports: [
    ...
    , PipeModule.forRoot()
    ....
  ],
Karl
la source
6
Cette solution était la seule qui fonctionnait pour moi. Il s'avère que les tuyaux doivent avoir un module
AJ Zane
J'ai aussi trouvé cela pour résoudre partiellement mon erreur de pipe non trouvée dans Ng 2.8. * De plus, j'avais des "avertissements" dactylographiés liés uniquement aux conventions de dénomination utilisées, qui, une fois résolues, ont contribué à ce que ce tube personnalisé se transforme correctement et soit finalement trouvé dans le modèle.
CNSKnight
C'est vraiment la seule solution qui a fonctionné pour moi! J'ai essayé tout le module partagé, mais cette solution a fonctionné comme un charme. Merci @Karl!
lulu88
comment pouvons-nous tester cela dans notre test de composants,
apoorva
2
Merci! Mon problème était que j'ai raté "exports: [myPipe]" en pensant que les exportations sont uniquement pour les modules!
Rafique Mohammed
55

Vous devez inclure votre pipe dans la déclaration du module:

declarations: [ UsersPipe ],
providers: [UsersPipe]
Yuvals
la source
5
Juste une note, à l'origine, je viens d'inclure le tuyau dans les fournisseurs. Cela doit être inclus dans les déclarations et les fournisseurs dans le fichier du module.
Greg A
J'avais du mal jusqu'à ce que je suive votre suggestion. J'ai perdu environ 4 heures pour le comprendre. Merci pour la suggestion.
user1501382
5
Pourquoi n'est-ce pas documenté? La documentation indique You must include your pipe in the declarations array of the AppModule.: angular.io/guide/pipes . Quoi qu'il en soit, votre réponse résout également mon problème.
Martijn
Merci, Yuvals. J'ajoute un détail: déclaration du module où vous avez besoin du tube.
Vinicios Torres
5
N'oubliez pas d'inclure également exports: [UsersPipe]si le module va être importé par d'autres modules.
Precastic
18

Pour Ionic, vous pouvez faire face à plusieurs problèmes comme @Karl l'a mentionné. La solution qui fonctionne parfaitement pour les pages chargées paresseusement ioniques est:

  1. Créez un répertoire pipes avec les fichiers suivants: pipes.ts et pipes.module.ts

// contenu pipes.ts (il peut avoir plusieurs tuyaux à l'intérieur, n'oubliez pas de

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

// contenu de pipes.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. Inclure PipesModule dans la section importations app.module et @NgModule

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

  2. Incluez PipesModule dans chacun de vos .module.ts où vous souhaitez utiliser des canaux personnalisés. N'oubliez pas de l'ajouter dans la section importations. // Exemple. fichier: pages / ma-page-personnalisée / ma-page-personnalisée.module.ts

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

  3. C'est tout. Vous pouvez maintenant utiliser votre tuyau personnalisé dans votre modèle. Ex.

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

Timothée
la source
Ce fut une bouée de sauvetage pour ionique, merci. Parce que "ionic generate pipe ...." ne génère pas toutes les étapes nécessaires, comme la création de pipes.module.ts. Votre approche a parfaitement fonctionné. Notez que pour ionic v4, de petites modifications sont nécessaires dans les chemins d'importation.
royappa
1
J'ai trouvé que vous n'avez pas besoin des importations dans app.module.ts, de sorte que cette étape peut être omise. Ce doit être parce que le "module partagé" est de toute façon importé dans chaque autre module là où il est nécessaire. Ce serait bien si l'importation app.module fonctionnait globalement, mais j'ai essayé et ce n'est pas le cas.
royappa
Je suis toujours confronté à ceci: Fichier d'ERREUR DE CONSOLE: node_modules/@angular/core/fesm5/core.js: 4002: 0 ERROR Erreur: Uncaught (en promesse): NullInjectorError: StaticInjectorError (AppModule) [ToHtmlPipe -> DomSanitizer]: StaticInjectorEr (Plate-forme: core) [ToHtmlPipe -> DomSanitizer]: NullInjectorError: Aucun fournisseur pour DomSanitizer!
mircobabini
12

J'ai trouvé la réponse «module croisé» ci-dessus très utile à ma situation, mais je voudrais développer cela, car il y a une autre ride à considérer. Si vous avez un sous-module, il ne peut pas non plus voir les tuyaux dans le module parent dans mes tests. Pour cette raison également, vous devrez peut-être insérer des tuyaux dans leur propre module séparé.

Voici un résumé des étapes que j'ai suivies pour traiter les tuyaux qui ne sont pas visibles dans le sous-module:

  1. Retirez les tuyaux de SharedModule (parent) et placez-les dans PipeModule
  2. Dans SharedModule, importez PipeModule et exportez (pour les autres parties de l'application dépendant de SharedModule pour accéder automatiquement à PipeModule)
  3. Pour Sub-SharedModule, importez PipeModule, afin qu'il puisse accéder à PipeModule, sans avoir à réimporter SharedModule, ce qui créerait un problème de dépendance circulaire, entre autres problèmes.

Une autre note de bas de page à la réponse "cross module" ci-dessus: quand j'ai créé le PipeModule, j'ai supprimé la méthode statique forRoot et importé PipeModule sans cela dans mon module partagé. Ma compréhension de base est que forRoot est utile pour des scénarios tels que les singletons, qui ne s'appliquent pas nécessairement aux filtres.

sarora
la source
1
Merci d'avoir ajouté ceci. Cela n'a fonctionné pour moi qu'une fois qu'il a été ajouté à Sub-SharedModule
jmcgrath207
Ouais même ici, la partie qui me manquait était l'importation de PipesModule dans le Sub-SharedModule.
filet mignon
1

Suggérer une alternative réponse ici:

Il n'est pas nécessaire de créer un module séparé pour le tuyau , mais c'est certainement une alternative. Consultez la note de bas de page officielle de la documentation: https://angular.io/guide/pipes#custom-pipes

Vous utilisez votre tuyau personnalisé de la même manière que vous utilisez des tuyaux intégrés.
Vous devez inclure votre canal dans le tableau des déclarations de l'AppModule. Si vous choisissez d'injecter votre pipe dans une classe, vous devez le fournir dans le tableau des fournisseurs de votre NgModule.

Tout ce que vous avez à faire est d'ajouter votre tube au tableau des déclarations et le tableau des fournisseurs à l' moduleendroit où vous souhaitez utiliser le tube.

declarations: [
...
CustomPipe,
...
],
providers: [
...
CustomPipe,
...
]
ykadaru
la source
Mais un seul tuyau ne peut pas faire partie de 2 modules .... L'approche ci-dessus le rend plus accessible dans différents modules.
Himanshu Bansal
0

Remarque : uniquement si vous n'utilisez pas de modules angulaires

Pour une raison quelconque, ce n'est pas dans la documentation mais j'ai dû importer le tuyau personnalisé dans le composant

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

@Component({
    ...
    pipes:      [UsersPipe]
})
Sumama Waheed
la source
1
Dans le Plunker que vous avez publié ci-dessus, les tuyaux sont importés dans le module d'application (exactement comme vous le faites avec les composants eux-mêmes), ce qui rend le tuyau disponible pour tous les composants de ce module.
ABabin
Oh ok je regardais en fait le composant qui utilise réellement le tube personnalisé. Je ne savais pas qu'il pouvait être importé globalement dans le module d'application. Merci
Sumama Waheed
users-filter.pipe? pourquoi .pipe?
Nather Webber
1
C'est juste une convention de dénomination, le fichier s'appelle users-filter.pipe.ts
Sumama Waheed
2
@SachinThampan pourrait être parce que c'était à l'époque où angular était dans rc5 je pense ... les choses ont changé depuis, spécialement avec NgModule. Veuillez consulter la documentation pour 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
la source
-2

J'ai créé un module pour les tubes dans le même répertoire où mes tubes sont présents

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

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

    export class SharedPipeModule { }   

Maintenant, importez ce module dans app.module:

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

Maintenant, il peut être utilisé en important le même dans le module imbriqué

Amit Saini
la source