Ionic 3 - lazy loading pages don't see any pipes

I had upgraded to Ionic 3 and decorated my pages to be lazy loaded with @IonicPage. But that throws error

    ERROR Error: Uncaught (in promise): Error: Template parse errors:
    The pipe 'myPipe' could not be found 

There is a solution is to declare all the pipes in a module that to be imported with each page.module.ts file. Here is the pipes.module.ts file

import { NgModule } from '@angular/core';
import { BreakLine } from './breakLine';
import { Hashtag } from './hashtag';
import { Translator } from './translator';

@NgModule({
    declarations: [
        BreakLine,
        Hashtag,
        Translator
    ],
    imports: [

    ],
    exports: [
        BreakLine,
        Hashtag,
        Translator
    ]
    ,
})
export class PipesModule {}

Here is where to use the pipes.module

import { NgModule } from '@angular/core';
import { IonicPageModule } from 'ionic-angular';
import { LoginPage } from './login';
import { PipesModule } from '../../pipes/pipes.module'

@NgModule({
    declarations: [
        LoginPage,
    ],
    imports: [
        IonicPageModule.forChild(LoginPage),
        PipesModule
    ],
    exports: [
        LoginPage
    ]
})
export class LoginPageModule { }

This kind of a very repeatative code, it’s like what we used to do before by adding the pips in each page.
How can I import the pipes one time to be used by all pages?

1 Like

One way would be to give up on lazy page loading for the time being. That’s what I’ve done.

There got to be a way. You cannot even have a mix of lazy loaded and normal pages, coz you will end up with the pipes declared twice which is a nother error.

You’re certainly welcome to try to find one, and lots of people would probably be very grateful if you did. I tried pretty hard for several days and have come to the conclusion that it’s beyond my ability given the current state of available tooling.

If you have an app where pages are clearly separated, and share no common dependencies aside from framework ones, lazy page loading in its current state will probably work great for you. For any other situation, I think it’s a net lose at the moment.

2 Likes

Here is some suggestion, https://github.com/ngx-translate/core/issues/506#issuecomment-292924764 From ngx-translate.

But there is no real steps to follow.

I solved this by creating a pipe module (PipesModule)

import { NgModule } from '@angular/core';
import {pipe1} from "./pipe1";
import {pipe2} from "./pipe2";

@NgModule({
    declarations: [
        pipe1,
        pipe2
    ],
    imports: [

    ],
    exports: [
        pipe1,
        pipe2
    ]
})
export class PipesModule { }

and imported it in my lazy loaded module.ts file

import {NgModule} from '@angular/core';
import {IonicPageModule} from 'ionic-angular';
import {MyPage} from './my-page';
import {PipesModule} from "../../pipes/PipesModule";

@NgModule({
    declarations: [
        MyPage,
    ],
    imports: [
        IonicPageModule.forChild(MyPage),
        PipesModule
    ],
    exports: [
        MyPage
    ]
})
export class MyPageModule {
}

I could import it into app.module.ts file too and use it in the components that are not lazy loaded

[EDIT]
Take a look here https://ionicacademy.com/ionic-3-lazy-loading/ @5

5 Likes

hi, I am facing a problem…perhaps my pipe implementation is wrong. I am trying to pass country code and return the country name

pipe:

  import {Pipe} from '@angular/core';
  import { UserPersonalService } from '../../providers/user-personal-service';

  @Pipe({
     name: 'countryname'
  })
  export class CountryName {
    constructor(private userService: UserPersonalService){}

    transform(value, args) {

       this.userService.getCountries().subscribe(res => {
         for (let i of res){
            if (value === i.code){
                return i.name_en;
            }
        }
    });
   }
  }

@ page.html:

 {{ countryCode | countryname }}

pipe.module.ts:

 import { NgModule } from '@angular/core';
 import { CountryName } from "./pipes/country-name";

 @NgModule({
     declarations: [
        CountryName
     ],
     imports: [

     ],
     exports: [
        CountryName
     ]
 })
 export class PipesModule { }

Nothing is displayed at html side, what am I doing wrong ?

The only difference I can see between your code and mine, is the pipe. Mine looks a little different

import {Injectable, Pipe} from ‘@angular/core’;
import * as moment from ‘moment’;
import ‘moment/locale/da’;
@Pipe({
name: ‘HumanDate’
})
@Injectable()
export class HumanDate {

transform(value, args)
{
    if ( ! value )
    {
        return null;
    }
    moment.locale('da-dk');
    let m = moment(value, ["YYYY-MM-DD HH:mm:ss", "YYYY-MM-DD"]);
    return m.format(args);
}

}

Mine has an @Injectable() decorator attached

Thank for the info everyone.

I am however also experiencing a problem with pipes after converting my ChatsPage to lazy loading. As you can see below, it is complaining about the use of the following line in my chats.html.

    <h3 class="chat-time">{{item.timestamp | amDateFormat: 'D MMM YYYY'}}</h3>

ERROR Error: Uncaught (in promise): Error: Template parse errors:
The pipe 'amDateFormat' could not be found ("item.memberId2 && !item.lastMsg_read2))}">{{item.lastMsg_text}}</p>
        <h3 class="chat-time">{{[ERROR ->]item.timestamp | amDateFormat: 'D MMM YYYY'}}</h3>
      </ion-item>

"): ng:///ChatsPageModule/ChatsPage.html@28:32
Error: Template parse errors:
The pipe 'amDateFormat' could not be found ("item.memberId2 && !item.lastMsg_read2))}">{{item.lastMsg_text}}</p>
        <h3 class="chat-time">{{[ERROR ->]item.timestamp | amDateFormat: 'D MMM YYYY'}}</h3>
      </ion-item>

Question

Any idea how to handle amDateFormat (angular2-moment) with lazy loading?

I solved my issue by adding import {MomentModule} from 'angular2-moment'; to the chats.module.ts.

import { NgModule } from '@angular/core';
import { IonicPageModule } from 'ionic-angular';
import { ChatsPage } from './chats';
import {MomentModule} from 'angular2-moment';

@NgModule({
  declarations: [ChatsPage],
  imports: [IonicPageModule.forChild(ChatsPage), MomentModule],
})
export class ChatsPageModule { }

I highly recommend ditching moment for date-fns, especially if you are flirting with lazy loading. Moment does not play nicely with modern dead code reduction.

You’re certainly welcome to try to find one, and lots of people would probably be very grateful if you did. I tried pretty hard for several days and have come to the conclusion that it’s beyond my ability given the current state of available tooling.

If you have an app where pages are clearly separated, and share no common dependencies aside from framework ones, lazy page loading in its current state will probably work great for you. For any other situation, I think it’s a net lose at the moment.

Hi Rapropos, a year later do still feel this way about lazy loading? I have a very large app and I’ve been trying implement lazy loading the last 2 days without a great success and almost at the end road of giving up.

I’m going through this process now with Ionic 3.9.2. It certainly seems doable as long as there aren’t shared resources. I’ve just embedded the html for certain components (e.g. toolbar) in each page. I’m fortunate that there aren’t any pipes that are needed on more than one page. Well, there were but I worked around that.

Ionic 4/Capacitor uses Angular routing and has a very different implementation of lazy loading. That might be worth looking into. I doubt any more work will be done on this.