The pipe ' ' could not be found angular2 custom pipe
Asked Answered
R

11

140

I can't seem to fix this error. I have a search bar and an ngFor. I am trying to filter the array using a custom pipe like this:

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>

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

Angular versions:

"@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"
Rasmussen answered 17/8, 2016 at 22:18 Comment(4)
Did you include it in the Component's Pipes ?Irenairene
I just realized that was the reason. How come the angular example for custom pipe never does this: angular.io/resources/live-examples/pipes/ts/plnkr.htmlRasmussen
They defined it as global pipe. You can do the same to your custom pipe if you use it in many places and don't want to define in every single annotation.Irenairene
@SumamaWaheed I am pretty sure that it was there at some point in the docs, but you are correct the docs now don't mention/show it.Hawserlaid
D
181

Make sure you are not facing a "cross module" problem

If the component which is using the pipe, doesn't belong to the module which has declared the pipe component "globally" then the pipe is not found and you get this error message.

In my case I've declared the pipe in a separate module and imported this pipe module in any other module having components using the pipe.

I have declared a that the component in which you are using the pipe is

the Pipe Module

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

Usage in another module (e.g. app.module)

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

  @NgModule({
     imports: [
    ...
    , PipeModule.forRoot()
    ....
  ],
Douro answered 23/11, 2016 at 17:12 Comment(10)
This solution was the only one that worked for me. Turns out pipes are required to have a moduleCedell
I too found this to partially solve my pipe not found error in Ng 2.8.* Additionally, I had typescript "warnings" related only to the naming conventions in use, which upon solving these, contributed to this custom pipe transpiling properly and ultimately being found in the template.Dia
This is truly the only solution that worked for me! I tried the whole shared module thing, but this solution worked like a charm. Thank you @Karl!Pregnancy
how do we test this in our component test,Digenesis
Thanks! My problem was i missed "exports:[myPipe]" thinking that exports are only for modules!Amenable
the only way I got it to work out. Looks like pipes should not be in shared module with other components and directivesAsturias
I don't think adding the Pipe to a separate module is required at all. Check the offical docs: angular.io/guide/pipes#custom-pipes It says Pipes have to be declared and provided, so it can be injectible. @AJZaneStammel
@Asturias I am getting error : Failed: Template parse errors: The pipe 'keys' could not be found ("<div class="form-control-feedback" *ngFor="let control of controlsInternal"> <p *ngFor="let e[ERROR ->]rror of control?.errors | keys"> <span *ngIf="!control?.untouched && control.errors[error]">{"): ng:///DynamicTestModule/FormErrorsComponent.html@1:20 How can i resolve it ?Vineland
This solution worked for me except that PipeModule had to import CommonModule. More research revealed that pipe, directives, etc. can be declared in one module only. If you have to use your custom pipe in a single module/component then you can directly import the pipe. But if you are planning to reuse the pipe in multiple modules, then the only way is to create another module (like PipeModule above) and then import this module in other modules.Alan
For me this post pointed in the right direction. I learned that Angular doesn't like it if you use custom pipes from multiple modules. The error occured when I used a custoum pipe in a template, both declared in the same module. Then another custom pipe from another (shared) module wasn't found...Priscian
C
74

You need to include your pipe in module declaration:

declarations: [ UsersPipe ],
providers: [UsersPipe]
Chyme answered 30/1, 2017 at 22:59 Comment(7)
Just a note, I originally just included the pipe in the providers. This needs to be included in both declarations and providers in the module file.Clavius
I was struggling until i followed your suggestion. i wasted around 4 hr's to just figure it out. Thank you for the suggestion.Diecious
Why isn't this documented? The documentation states You must include your pipe in the declarations array of the AppModule. : angular.io/guide/pipes. Anyway, your answer also fixes my problem.Mingmingche
Thanks, Yuvals. I add a detail: declaration of module where you need the pipe.Bunin
Don't forget to also include exports: [UsersPipe] if the module is going to be imported by other modules.Omeromero
I think this should be marked as the correct answer. The marked answer is misleading; it's just an alternative... but the most straightforward answer is this.Stammel
I also like this answer. At first it did not seem to work for me because ng serve didn't pick up this change. I had to kill it and used the ng serve command again to rebuild everything.Kalikalian
U
24

For Ionic you can face multiple issues as @Karl mentioned. The solution which works flawlessly for ionic lazy loaded pages is:

  1. Create pipes directory with following files: pipes.ts and pipes.module.ts

// pipes.ts content (it can have multiple pipes inside, just remember to

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

// pipes.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. Include PipesModule into app.module and @NgModule imports section

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

  2. Include PipesModule in each of your .module.ts where you want to use custom pipes. Don't forget to add it into imports section. // Example. file: pages/my-custom-page/my-custom-page.module.ts

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

  3. Thats it. Now you can use your custom pipe in your template. Ex.

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

Ursula answered 25/4, 2018 at 10:51 Comment(3)
This was a lifesaver for ionic, thanks. Because "ionic generate pipe ...." does not generate all the steps needed, like creating the pipes.module.ts. Your approach worked perfectly. Note, for ionic v4, some small changes are needed to the import paths.Prado
I found that you don't need the imports in app.module.ts, so that step can be omitted. It must be because it the "shared module" is anyway being imported into each other module where it is needed. It would be nice if the app.module import worked globally, but I tried and it doesn't.Prado
I'm still facing this: CONSOLE ERROR file: node_modules/@angular/core/fesm5/core.js:4002:0 ERROR Error: Uncaught (in promise): NullInjectorError: StaticInjectorError(AppModule)[ToHtmlPipe -> DomSanitizer]: StaticInjectorError(Platform: core)[ToHtmlPipe -> DomSanitizer]: NullInjectorError: No provider for DomSanitizer!Outlandish
A
14

I found the "cross module" answer above very helpful to my situation, but would want to expand on that, as there is another wrinkle to consider. If you have a submodule, it also can't see the pipes in the parent module in my testing. For that reason also, you may need to put pipes into there own separate module.

Here's a summary of the steps I took to address pipes not being visible in the submodule:

  1. Take pipes out of (parent) SharedModule and put into PipeModule
  2. In SharedModule, import PipeModule and export (for other parts of app dependent on SharedModule to automatically gain access to PipeModule)
  3. For Sub-SharedModule, import PipeModule, so it can gain access to PipeModule, without having to re-import SharedModule which would create a circular dependency issue, among other problems.

Another footnote to the above "cross module" answer: when I created the PipeModule I removed the forRoot static method and imported PipeModule without that in my shared module. My basic understanding is that forRoot is useful for scenarios like singletons, which don't apply to filters necessarily.

Alvita answered 6/1, 2017 at 16:40 Comment(4)
Thank you for adding this. It only worked for me once it was added to Sub-SharedModuleLyonnesse
Yeah same here, the part I was missing was importing PipesModule into the Sub-SharedModule.Pindling
I'm still confused as to what actually fixes the issue. In #2 you say 'export for other parts of app to automatically gain access' but then in #3 you say to import PipeModule into the Sub-SharedModule. The Sub-SharedModule already is importing SharedModule right? Why do we need to import PipeModule as well, if we're exporting it already in SharedModule?Leprosarium
Good question - to be clear.. by Sub-SharedModule i mean a module that is imported into SharedModule, NOT something that is already importing SharedModule. In this scenario, the Sub SharedModule doesn't get access to PipesModule.Alvita
S
5

Suggesting an alternative answer here:

Making a separate module for the Pipe is not required, but is definitely an alternative. Check the official docs footnote: https://angular.io/guide/pipes#custom-pipes

You use your custom pipe the same way you use built-in pipes.
You must include your pipe in the declarations array of the AppModule . If you choose to inject your pipe into a class, you must provide it in the providers array of your NgModule.

All you have to do is add your pipe to the declarations array, and the providers array in the module where you want to use the Pipe.

declarations: [
...
CustomPipe,
...
],
providers: [
...
CustomPipe,
...
]
Stammel answered 20/5, 2019 at 16:11 Comment(1)
But a single pipe can not be a part of 2 modules.... The above approach make it more approachable in different modules.Triplenerved
A
1

If you see this error when running tests, make sure you have imported the module the pipe belongs to, e.g.:

    beforeEach(async(() => {
        TestBed.configureTestingModule({
            imports: [CustomPipeModule],
            declarations: [...],
            providers: [...],
            ...
        }).compileComponents();
    }));
Alvaalvan answered 14/10, 2020 at 12:17 Comment(1)
Very good catch! Thanks!Glutelin
U
1

Custom Pipes: When a custom pipe is created, It must be registered in Module and Component that is being used.

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)+'...'
    } 
  }
}

Add Pipe Decorator

 @Pipe({
        name:'summary'
    })

and refer

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

//summary is the name declared in Pipe decorator

Underclothes answered 23/12, 2020 at 15:5 Comment(0)
R
0

Note : Only if you are not using angular modules

For some reason this is not in the docs but I had to import the custom pipe in the component

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

@Component({
    ...
    pipes:      [UsersPipe]
})
Rasmussen answered 17/8, 2016 at 23:11 Comment(5)
In the Plunker you posted above, the pipes are imported in the app module (exactly as you do with the components themselves) which makes the pipe available for all components in that module.Taunton
Oh ok I was actually looking at the component that actually uses the custom pipe. I didn't know it could be imported globally in the app module . ThanksRasmussen
users-filter.pipe? why .pipe?Accretion
That's just a naming convention, the file is called users-filter.pipe.tsRasmussen
@SachinThampan could be because this was when angular was in rc5 I think..things changed since then specially with NgModule. Please look at the docs for NgModuleRasmussen
B
0

I have faced the same problem.

Initially it was a "cross module" problem as described here

but that is not all.

Running application for long time - app wasnt able to figure out with this new imported Pipe.

I re-run ng serve command - and finnally cross module is gone

Bonze answered 15/4, 2022 at 16:0 Comment(0)
D
-1

I have created a module for pipes in the same directory where my pipes are present

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

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

    export class SharedPipeModule { }   

Now import that module in app.module:

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

Now it can be used by importing the same in the nested module

Dorset answered 16/1, 2018 at 14:41 Comment(0)
F
-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.
Farrier answered 29/3, 2019 at 6:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.