2
votes

I have a very simple Pipe in Angular 5

import { Pipe, Injectable } from '@angular/core';

@Pipe({
    name: "default"
})
@Injectable()
export class DefaultPipe {
    transform(value: string, fallback: string): string {
        let image = "";
        if (value) {
            image = value;
        } else {
            image = fallback;
        }
        return image;
    }
}

and I use it in a very simple way just for demonstration

<div>
    {{ 'somthing' | default }}
</div> 

I have also added in provider section in app.module.ts

@NgModule({
    declarations: [
        AppComponent,
        DefaultPipe // <-- Here
    ],
    imports: [
        ....
    ],
    providers: [
        ....
    ],
    bootstrap: [AppComponent]
})
export class AppModule { }

when you use it in an normal component such as

app.component.html

it works fine, but if you use it in a component which is used in a child route it gives this error:

compiler.js:486 Uncaught Error: Template parse errors: The pipe 'default' could not be found ("

{{[ERROR ->] 'somthing' | default }} "): ng:///AppRoutingModule/LoginComponent.html@75:6 at syntaxError (compiler.js:486) at TemplateParser.webpackJsonp../node_modules/@angular/compiler/esm5/compiler.js.TemplateParser.parse (compiler.js:24674) at JitCompiler.webpackJsonp../node_modules/@angular/compiler/esm5/compiler.js.JitCompiler._parseTemplate (compiler.js:34629) at JitCompiler.webpackJsonp../node_modules/@angular/compiler/esm5/compiler.js.JitCompiler._compileTemplate (compiler.js:34604) at compiler.js:34505 at Set.forEach () at JitCompiler.webpackJsonp../node_modules/@angular/compiler/esm5/compiler.js.JitCompiler._compileComponents (compiler.js:34505) at compiler.js:34375 at Object.then (compiler.js:475) at JitCompiler.webpackJsonp../node_modules/@angular/compiler/esm5/compiler.js.JitCompiler._compileModuleAndComponents (compiler.js:34374)

To Solve:

I added this module as share.module.ts

import { NgModule } from '@angular/core';
import { DefaultPipe } from './core/pipes/default.pipe';

@NgModule({
    declarations: [DefaultPipe],
    exports: [DefaultPipe]
})
export class SharedModule { }

and used it in 2 places, one in app.module.ts:

@NgModule({
declarations: [
    AppComponent,
],
imports: [
    ...
    // other modules
    ...
    SharedModule
],
providers: [
    ....
],
bootstrap: [AppComponent]

}) export class AppModule { }

and one in route.module.ts

@NgModule({
    declarations: [
        ....
    ],
    imports: [
        ....
        SharedModule
    ],
    exports: [
        RouterModule,
    ]
})

export class AppRoutingModule { }
3
could you please add the module in which you declare the LoginComponent? - Jota.Toledo
Why vote-down? you put all the effort to solve a problem with many explains and here you go, you get a vote-down, THANKS SO MUCH !!! - Ehsan Zargar Ershadi

3 Answers

4
votes

The best practice for creating helper components, pipes or directives is to create a SharedModule and put that stuff inside.

Components, Directives and Pipes don't work like services. A service you can inject it in the AppModule's services array and that will work for children too.

A Pipe, Directive or Component you have to declare them in an NgModule and then import it where you need it, because they can ONLY belong to 1 Module. (But that module can be imported as many times as you want!)

Therefore, the best thing you could do is to create a SharedModule with the following:

@NgModule({
  imports: [ ... ],
  declarations: [ DefaultPipe ],
  exports: [ DefaultPipe ]
})
export class SharedModule { }

And then in AppModule you import SharedModule like this:

imports: [ SharedModule ]

And now, if you want to use it in your LoginComponent or in any other part of your application, you import your SharedModule in the module for that component.

0
votes

Reference : here

Custom pipe:

First of all, no @Injectable() since it's not a service that you'll define in the constructor. Then, you need to import the PipeTransform provided in the '@angular/core' and implements it.

Example:

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
    name: "default"
})

export class DefaultPipe implements PipeTransform {
    transform(value: string, fallback: string): string {
        let image = "";
        if (value) {
            image = value;
        } else {
            image = fallback;
        }
        return image;
    }
}
0
votes

You dont need to use the Injectable decorator on the pipe, so you can remove that.

Furthermore, as already suggested in other answers, I would recommend you to explicitely implement the PipeTransform interface in order to be consistent with the pipe API.

compiler.js:486 Uncaught Error: Template parse errors: The pipe 'default' could not be found ("

{{[ERROR ->] 'somthing' | default }} "): ng:///AppRoutingModule/LoginComponent.html@75:6 at syntaxError (compiler.js:486)

is basically saying that your pipe wasnt neither declared or imported in the module, in whichLoginComponent is declared.

The simplest and cleanest solution would be to declare/export the pipe inside of a new NgModule class, that you can then import into every module that declares a component that uses the pipe. For example:

@NgModule({
  declarations: [DefaultPipe],
  exports: [DefaultPipe]
})
export class DefaultPipeModule{}

@NgModule({
  imports: [DefaultPipeModule],
  declarations: [LoginComponent]
})
export class FooModule {}

@NgModule({
  imports: [DefaultPipeModule],
  declarations: [FooComponent] // fooComponent also uses the default pipe, so we need to import its module
})
export class SomeOtherModule{}