ไม่พบท่อ "" ไปป์แบบกำหนดเอง angular2


106

ดูเหมือนจะแก้ไขข้อผิดพลาดนี้ไม่ได้ ฉันมีแถบค้นหาและ ngFor ฉันกำลังพยายามกรองอาร์เรย์โดยใช้ไปป์ที่กำหนดเองดังนี้:

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

การใช้งาน:

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

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

ข้อผิดพลาด:

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

1
คุณรวมไว้ในท่อของส่วนประกอบหรือไม่
Harry Ninh

ฉันเพิ่งรู้ว่านั่นคือเหตุผล ทำไมตัวอย่างเชิงมุมสำหรับท่อที่กำหนดเองไม่เคยทำเช่นนี้: angular.io/resources/live-examples/pipes/ts/plnkr.html
Waheed

พวกเขากำหนดให้เป็นท่อระดับโลก คุณสามารถทำเช่นเดียวกันกับไปป์ที่กำหนดเองได้หากคุณใช้มันในหลาย ๆ ที่และไม่ต้องการกำหนดในทุกคำอธิบายประกอบ
Harry Ninh

@SumamaWaheed ฉันค่อนข้างมั่นใจว่ามันมีอยู่ในบางจุดในเอกสาร แต่คุณแก้ไขเอกสารตอนนี้ไม่ได้พูดถึง / แสดง
Michelangelo

คำตอบ:


144

ตรวจสอบให้แน่ใจว่าคุณไม่ประสบปัญหา "ข้ามโมดูล"

หากส่วนประกอบที่ใช้ไปป์ไม่ได้เป็นของโมดูลที่ประกาศส่วนประกอบไปป์ "ทั่วโลก" แสดงว่าไม่พบไพพ์และคุณได้รับข้อความแสดงข้อผิดพลาดนี้

ในกรณีของฉันฉันได้ประกาศไปป์ในโมดูลแยกต่างหากและนำเข้าโมดูลท่อนี้ในโมดูลอื่น ๆ ที่มีส่วนประกอบโดยใช้ท่อ

ฉันได้ประกาศว่าส่วนประกอบที่คุณใช้ท่อคือ

โมดูลท่อ

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

การใช้งานในโมดูลอื่น (เช่น app.module)

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

  @NgModule({
     imports: [
    ...
    , PipeModule.forRoot()
    ....
  ],

6
วิธีนี้เป็นวิธีเดียวที่ใช้ได้ผลสำหรับฉัน ปรากฎว่าท่อต้องมีโมดูล
AJ Zane

ฉันพบสิ่งนี้เช่นกันเพื่อแก้ข้อผิดพลาดไม่พบท่อของฉันใน Ng 2.8 บางส่วน * นอกจากนี้ฉันมี "คำเตือน" typescript ที่เกี่ยวข้องกับรูปแบบการตั้งชื่อที่ใช้เท่านั้นซึ่งเมื่อแก้ปัญหาเหล่านี้มีส่วนทำให้ไปป์ที่กำหนดเองนี้แสดงอย่างถูกต้องและในที่สุดก็พบ ในเทมเพลต
CNSKnight

นี่เป็นทางออกเดียวที่เหมาะกับฉันอย่างแท้จริง! ฉันลองใช้โมดูลที่ใช้ร่วมกันทั้งหมด แต่โซลูชันนี้ใช้งานได้ดี ขอบคุณ @Karl!
lulu88

เราจะทดสอบสิ่งนี้ได้อย่างไรในการทดสอบส่วนประกอบของเรา
apoorva

2
ขอบคุณ! ปัญหาของฉันคือฉันพลาด "การส่งออก: [myPipe]" โดยคิดว่าการส่งออกมีไว้สำหรับโมดูลเท่านั้น!
Rafique Mohammed

55

คุณต้องรวมไปป์ของคุณในการประกาศโมดูล:

declarations: [ UsersPipe ],
providers: [UsersPipe]

5
โปรดทราบว่าเดิมทีฉันเพิ่งรวมท่อในผู้ให้บริการ สิ่งนี้จะต้องรวมอยู่ในทั้งการประกาศและผู้ให้บริการในไฟล์โมดูล
Greg A

ฉันดิ้นรนจนกว่าฉันจะทำตามคำแนะนำของคุณ ฉันเสียเวลาไปประมาณ 4 ชม. เพื่อคิดออก ขอบคุณสำหรับข้อเสนอแนะ
user1501382

5
เหตุใดจึงไม่มีเอกสารนี้ เอกสารรัฐYou must include your pipe in the declarations array of the AppModule.: angular.io/guide/pipes อย่างไรก็ตามคำตอบของคุณก็ช่วยแก้ปัญหาของฉันได้เช่นกัน
Martijn

ขอบคุณ Yuvals ฉันเพิ่มรายละเอียด: การประกาศโมดูลที่คุณต้องการท่อ
Vinicios Torres

5
อย่าลืมระบุexports: [UsersPipe]ด้วยว่าโมดูลอื่นกำลังจะนำเข้าโมดูลหรือไม่
Precastic

18

สำหรับ Ionic คุณสามารถเผชิญกับปัญหาต่างๆตามที่ @Karl กล่าวถึง วิธีแก้ปัญหาที่ทำงานได้อย่างไม่มีที่ติสำหรับหน้าที่โหลดแบบอิออนคือ:

  1. สร้างไดเร็กทอรีไปป์ด้วยไฟล์ต่อไปนี้: pip.tsและpip.module.ts

// เนื้อหา pipe.ts (สามารถมีหลายท่อภายในได้อย่าลืม

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

// เนื้อหา pip.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. รวม PipesModule ไว้ในส่วนการนำเข้า app.module และ @NgModule

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

  2. รวม PipesModule ไว้ใน. module.ts แต่ละอันที่คุณต้องการใช้ไปป์แบบกำหนดเอง อย่าลืมเพิ่มลงในส่วนการนำเข้า // ตัวอย่าง. ไฟล์: pages / my-custom-page / my-custom-page.module.ts

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

  3. แค่นั้นแหละ. ตอนนี้คุณสามารถใช้ไปป์ที่กำหนดเองในเทมเพลตของคุณ เช่น

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


นี่คือตัวช่วยชีวิตสำหรับไอออนิกขอบคุณ เนื่องจาก "สร้างท่อไอออนิก .... " ไม่ได้สร้างขั้นตอนทั้งหมดที่จำเป็นเช่นการสร้าง pip.module.ts แนวทางของคุณทำงานได้อย่างสมบูรณ์แบบ หมายเหตุสำหรับไอออนิก v4 จำเป็นต้องมีการเปลี่ยนแปลงเล็กน้อยกับพา ธ อิมพอร์ต
royappa

1
ฉันพบว่าคุณไม่ต้องการการนำเข้าใน app.module.ts ดังนั้นจึงสามารถข้ามขั้นตอนนั้นไปได้ จะต้องเป็นเพราะ "โมดูลที่ใช้ร่วมกัน" จะถูกนำเข้าสู่โมดูลอื่น ๆ ที่จำเป็น คงจะดีไม่น้อยหากการนำเข้า app.module ทำงานได้ทั่วโลก แต่ฉันลองแล้วไม่เป็นเช่นนั้น
royappa

ฉันยังคงเผชิญกับสิ่งนี้: ไฟล์ CONSOLE ERROR: node_modules/@angular/core/fesm5/core.js: 4002: 0 ข้อผิดพลาดข้อผิดพลาด: Uncaught (ในสัญญา): NullInjectorError: StaticInjectorError (AppModule) [ToHtmlPipe -> DomSanitizer]: StaticInjectorError (Platform: core) [ToHtmlPipe -> DomSanitizer]: NullInjectorError: ไม่มีผู้ให้บริการสำหรับ DomSanitizer!
mircobabini

13

ฉันพบว่าคำตอบ "โมดูลไขว้" ข้างต้นมีประโยชน์มากสำหรับสถานการณ์ของฉัน แต่ต้องการขยายความเนื่องจากมีริ้วรอยอื่นที่ต้องพิจารณา หากคุณมีโมดูลย่อยก็จะมองไม่เห็นท่อในโมดูลหลักในการทดสอบของฉัน ด้วยเหตุนี้คุณอาจต้องใส่ท่อลงในโมดูลแยกต่างหาก

นี่คือสรุปขั้นตอนที่ฉันดำเนินการเพื่อแก้ไขไปป์ที่ไม่ปรากฏในโมดูลย่อย:

  1. นำท่อออกจาก (parent) SharedModule และใส่ลงใน PipeModule
  2. ใน SharedModule ให้นำเข้า PipeModule และส่งออก (สำหรับส่วนอื่น ๆ ของแอปที่ขึ้นอยู่กับ SharedModuleเพื่อเข้าถึง PipeModule โดยอัตโนมัติ)
  3. สำหรับ Sub-SharedModule ให้นำเข้า PipeModule เพื่อให้สามารถเข้าถึง PipeModule ได้โดยไม่ต้องนำเข้า SharedModule ซ้ำซึ่งจะสร้างปัญหาการพึ่งพาแบบวงกลมท่ามกลางปัญหาอื่น ๆ

เชิงอรรถอีกประการหนึ่งสำหรับคำตอบของ "โมดูลข้าม" ข้างต้น: เมื่อฉันสร้าง PipeModule ฉันได้ลบเมธอดแบบคงที่ forRoot และนำเข้า PipeModule โดยไม่มีสิ่งนั้นในโมดูลที่ใช้ร่วมกันของฉัน ความเข้าใจพื้นฐานของฉันคือ forRoot มีประโยชน์สำหรับสถานการณ์เช่น singletons ซึ่งไม่ได้ใช้กับตัวกรองเสมอไป


2
ขอบคุณสำหรับการเพิ่มสิ่งนี้ มันใช้ได้ผลสำหรับฉันเมื่อมันถูกเพิ่มไปยัง Sub-SharedModule
jmcgrath207

เหมือนกันที่นี่ส่วนที่ฉันขาดหายไปคือการนำเข้า PipesModule ไปยัง Sub-SharedModule
เนื้อสันใน

1

แนะนำคำตอบอื่นที่นี่:

ไม่จำเป็นต้องสร้างโมดูลแยกต่างหากสำหรับ Pipe แต่เป็นทางเลือกที่แน่นอน ตรวจสอบเชิงอรรถของเอกสารอย่างเป็นทางการ: https://angular.io/guide/pipes#custom-pipes

คุณใช้ท่อแบบกำหนดเองแบบเดียวกับที่คุณใช้ท่อในตัว
คุณต้องรวมไปป์ของคุณในอาร์เรย์การประกาศของ AppModule หากคุณเลือกที่จะฉีดไปป์ของคุณในคลาสคุณต้องระบุไว้ในอาร์เรย์ผู้ให้บริการของ NgModule ของคุณ

สิ่งที่คุณต้องทำคือเพิ่มไปป์ของคุณไปยังอาร์เรย์การประกาศและอาร์เรย์ผู้ให้บริการในmoduleตำแหน่งที่คุณต้องการใช้ Pipe

declarations: [
...
CustomPipe,
...
],
providers: [
...
CustomPipe,
...
]

แต่ท่อเดียวไม่สามารถเป็นส่วนหนึ่งของ 2 โมดูล .... แนวทางข้างต้นทำให้สามารถเข้าถึงได้มากขึ้นในโมดูลต่างๆ
Himanshu Bansal

0

หมายเหตุ:เฉพาะในกรณีที่คุณไม่ได้ใช้โมดูลเชิงมุม

ด้วยเหตุผลบางอย่างสิ่งนี้ไม่ได้อยู่ในเอกสาร แต่ฉันต้องนำเข้าไปป์ที่กำหนดเองในส่วนประกอบ

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

@Component({
    ...
    pipes:      [UsersPipe]
})

1
ใน Plunker ที่คุณโพสต์ไว้ด้านบนไปป์จะถูกนำเข้าในโมดูลแอพ (เหมือนกับที่คุณทำกับส่วนประกอบเอง) ซึ่งทำให้ไปป์พร้อมใช้งานสำหรับส่วนประกอบทั้งหมดในโมดูลนั้น
ABabin

โอเคฉันกำลังดูส่วนประกอบที่ใช้ท่อที่กำหนดเองจริงๆ ฉันไม่ทราบว่าสามารถนำเข้าได้ทั่วโลกในโมดูลแอป ขอบคุณ
Sumama Waheed

ผู้ใช้ filter.pipe? ทำไม. ท่อ?
Nather Webber

1
นั่นเป็นเพียงหลักการตั้งชื่อไฟล์นี้เรียกว่า users-filter.pipe.ts
Waheed

2
@SachinThampan อาจเป็นเพราะนี่คือตอนที่ angular อยู่ใน rc5 ฉันคิดว่า .. สิ่งต่าง ๆ เปลี่ยนไปตั้งแต่นั้นมาโดยเฉพาะกับ NgModule โปรดดูเอกสารสำหรับ NgModule
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.

-2

ฉันได้สร้างโมดูลสำหรับไปป์ในไดเร็กทอรีเดียวกับที่มีไพพ์ของฉันอยู่

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

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

    export class SharedPipeModule { }   

ตอนนี้นำเข้าโมดูลนั้นใน app.module:

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

ตอนนี้สามารถใช้ได้โดยการนำเข้าสิ่งเดียวกันในโมดูลที่ซ้อนกัน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.