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"
Stefan Falk
  • 23,898
  • 50
  • 191
  • 378
Sumama Waheed
  • 3,579
  • 3
  • 18
  • 32
  • 1
    Did you include it in the Component's Pipes ? – Harry Ninh Aug 17 '16 at 23:09
  • I just realized that was the reason. How come the angular example for custom pipe never does this: https://angular.io/resources/live-examples/pipes/ts/plnkr.html – Sumama Waheed Aug 17 '16 at 23:12
  • 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. – Harry Ninh Aug 17 '16 at 23:27
  • @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. – Michelangelo Aug 18 '16 at 00:07

11 Answers11

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()
    ....
  ],
Stefan Falk
  • 23,898
  • 50
  • 191
  • 378
Karl
  • 3,099
  • 3
  • 22
  • 24
  • 8
    This solution was the only one that worked for me. Turns out pipes are required to have a module – AJ Zane Dec 23 '16 at 23:08
  • 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. – CNSKnight Apr 01 '17 at 16:27
  • 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! – lulu88 Jun 24 '17 at 19:20
  • how do we test this in our component test, – apoorva Dec 20 '17 at 11:52
  • 2
    Thanks! My problem was i missed "exports:[myPipe]" thinking that exports are only for modules! – Rafique Mohammed Apr 26 '18 at 08:29
  • the only way I got it to work out. Looks like pipes should not be in shared module with other components and directives – karlis May 12 '18 at 11:29
  • I don't think adding the Pipe to a separate module is required at all. Check the offical docs: https://angular.io/guide/pipes#custom-pipes It says Pipes have to be declared and **provided**, so it can be injectible. @AJZane – ykadaru May 15 '19 at 14:25
  • @karlis I am getting error : Failed: Template parse errors: The pipe 'keys' could not be found (" – Sahal Jun 24 '20 at 04:47
  • 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. – maniB Oct 16 '20 at 05:59
  • 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... – NoNine Jul 26 '22 at 08:57
75

You need to include your pipe in module declaration:

declarations: [ UsersPipe ],
providers: [UsersPipe]
Yuvals
  • 3,094
  • 5
  • 32
  • 60
  • 5
    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. – Greg A Mar 13 '17 at 16:19
  • I was struggling until i followed your suggestion. i wasted around 4 hr's to just figure it out. Thank you for the suggestion. – user1501382 Apr 14 '17 at 19:07
  • 7
    Why isn't this documented? The documentation states `You must include your pipe in the declarations array of the AppModule.` : https://angular.io/guide/pipes. Anyway, your answer also fixes my problem. – Martijn Oct 13 '17 at 14:01
  • Thanks, Yuvals. I add a detail: declaration of module where you need the pipe. – Vinicios Torres Nov 26 '17 at 01:47
  • 6
    Don't forget to also include `exports: [UsersPipe]` if the module is going to be imported by other modules. – Precastic Jan 28 '18 at 10:26
  • 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. – ykadaru May 15 '19 at 14:26
  • 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. – Marcus Jun 09 '20 at 00:00
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>

Timothy
  • 3,213
  • 2
  • 21
  • 34
  • 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. – royappa Jun 02 '19 at 00:10
  • 1
    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. – royappa Jun 02 '19 at 00:20
  • 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! – mircobabini Jul 01 '20 at 05:27
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.

sarora
  • 913
  • 9
  • 20
  • 2
    Thank you for adding this. It only worked for me once it was added to Sub-SharedModule – jmcgrath207 Dec 09 '17 at 08:15
  • Yeah same here, the part I was missing was importing PipesModule into the Sub-SharedModule. – tenderloin Apr 26 '18 at 00:35
  • 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? – Ebsan Dec 17 '20 at 18:43
  • 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. – sarora Jan 15 '21 at 21:26
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,
...
]
ykadaru
  • 1,108
  • 2
  • 16
  • 32
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();
    }));
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

Mario Petrovic
  • 7,500
  • 14
  • 42
  • 62
sarath chandra
  • 181
  • 1
  • 4
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]
})
Sumama Waheed
  • 3,579
  • 3
  • 18
  • 32
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

shutsman
  • 2,357
  • 1
  • 12
  • 23
-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

TylerH
  • 20,799
  • 66
  • 75
  • 101
-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.