web-dev-qa-db-ja.com

動的パイプAngular 2

コンポーネント内のリストに使用するパイプを渡すことができるコンポーネントを作成しようとしています。私がテストして答えを探して見つけたものから、唯一の解決策は次のようなものを作成するようです:

<my-component myFilter="sortByProperty"></my-component>

my-component テンプレート:

<li *ngFor="#item of list | getPipe:myFilter"></li>

次に、myFilterを正しいパイプロジックにマップして実行しますが、これは少しダーティで最適ではありません。

Angular 1なので、これらの線に沿って何かを行うことになるので、彼らはこの問題のより良い解決策を思い付くと思いました。

Angular 2でこれを行うより良い方法はありませんか?

16
Chrillewoodz

Borislemkeの答えに基づいて、eval()を必要とせず、私がかなりきれいだと思う解決策があります:

dynamic.pipe.ts:

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


@Pipe({
  name: 'dynamicPipe'
})
export class DynamicPipe implements PipeTransform {

    public constructor(private injector: Injector) {
    }

    transform(value: any, pipeToken: any, pipeArgs: any[]): any {
        if (!pipeToken) {
            return value;
        }
        else {
            let pipe = this.injector.get(pipeToken);
            return pipe.transform(value, ...pipeArgs);
        }
    }
}

app.module.ts:

// …
import { DynamicPipe } from './dynamic.pipe';

@NgModule({
  declarations: [
    // …
    DynamicPipe,
  ],
  imports: [
    // …
  ],
  providers: [
    // list all pipes you would like to use
    PercentPipe,
    ],
  bootstrap: [AppComponent]
})
export class AppModule { }

app.component.ts:

import { Component, OnInit } from '@angular/core';
import { PercentPipe } from '@angular/common';

@Component({
  selector: 'app-root',
  template: `
    The following should be a percentage: 
    {{ myPercentage | dynamicPipe: myPipe:myPipeArgs }}
    `,
  providers: []
})

export class AppComponent implements OnInit {
  myPercentage = 0.5;
  myPipe = PercentPipe;
  myPipeArgs = [];
}
31
balu

これに取り組む最も簡単な方法は、HTMLテンプレートでパイプを使用せず、代わりに(DIを使用して)コンポーネントのコンストラクターにパイプを挿入し、機能的に変換を適用することです。これは、Observableマップまたは同様のrxjsストリームで非常にうまく機能します。

3

私はなんとか機能させることができました、それは少し汚くて邪悪です(評価付き)が、それは私にとってはトリックです。私の場合、各行に異なるデータ型(タイトル、URL、日付、ステータスなど)を持つテーブルコンポーネントがあります。私のデータベースでは、ステータスは1 as enabledまたは0 for disabled。もちろん、ユーザーに対して有効/無効を表示する方が望ましいです。また、私のタイトル列は多言語であり、enまたはidをキーとするオブジェクトになります。

// Example row object:
title: {
    "en": "Some title in English",
    "id": "Some title in Indonesian"
},
status: 1 // either 1 or 0

理想的には、データを変換してアプリのユーザーに表示するために2つの異なるパイプが必要です。 translateTitlegetStatusのようなもので問題ありません。親のパイプをdynamicPipeと呼びましょう。

/// some-view.html
{{ title | dynamicPipe:'translateTitle' }}
{{ status | dynamicPipe:'getStatus' }}


/// dynamic.pipe.ts
//...import Pipe and PipeTransform

@Pipe({name:'dynamicPipe'})
export class DynamicPipe implements PipeTransform {

    transform(value:string, modifier:string) {
        if (!modifier) return value;
        return eval('this.' + modifier + '(' + value + ')')
    }

    getStatus(value:string|number):string {
        return value ? 'enabled' : 'disabled'
    }

    translateTitle(value:TitleObject):string {
        // defaultSystemLanguage is set to English by default
        return value[defaultSystemLanguage]
    }
}

私はおそらくevalを使うことにかなりの嫌悪感を抱くでしょう。それが役に立てば幸い!

更新:必要な場合

posts = {
    content: [
        {
            title:
                {
                    en: "Some post title in English",
                    es: "Some post title in Spanish"
                },
            url: "a-beautiful-post",
            created_at: "2016-05-15 12:21:38",
            status: 1
        },
        {
            title:
                {
                    en: "Some post title in English 2",
                    es: "Some post title in Spanish 2"
                },
            url: "a-beautiful-post-2",
            created_at: "2016-05-13 17:53:08",
            status: 0
        }
    ],
    pipes: ['translateTitle', null, 'humanizeDate', 'getStatus']
}

<table>
    <tr *ngFor="let row in posts">
        <td *ngFor="let column in row; let i = index">{{ column | dynamicPipe:pipes[i] }}</td>
    </tr>
</table>

戻ります:

| title          | url            | date           | status         |
| Some post t...   a-beautiful...   an hour ago      enabled
| Some post ...2   a-beautifu...2   2 days ago       disabled
3
borislemke

残念ながらそうは思いません。これは、必要な動的パイプの文字列を返す関数があるangular1と同じです。

彼らがそれをどのように表示するかについてのドキュメントを見てください。

https://angular.io/docs/ts/latest/guide/pipes.html

template: `
   <p>The hero's birthday is {{ birthday | date:format }}</p>
   <button (click)="toggleFormat()">Toggle Format</button>
`

次にコントローラーで:

get format()   { return this.toggle ? 'shortDate' : 'fullDate'}

悲しいかな、それはもっと悪いことかもしれません! :)

@Baluに基づいて構築すると、Angular 9

import { Injector, Pipe, PipeTransform } from '@angular/core';
import { PercentPipe, CurrencyPipe, DecimalPipe } from '@angular/common';

@Pipe({
    name: 'dynamicPipe'
})

export class DynamicPipe implements PipeTransform {

    public constructor(private injector: Injector, private percentPipe: PercentPipe) {
    }

    transform(value: any, pipeToken: any, pipeArgs: any[]): any {

        const MAP = { 'currency': CurrencyPipe, 'decimal': DecimalPipe, 'percent': PercentPipe }

        if (pipeToken && MAP.hasOwnProperty(pipeToken)) {
            var pipeClass = MAP[pipeToken];
            var pipe = this.injector.get(pipeClass);
            if (Array.isArray(pipeArgs)) {
                return pipe.transform(value, ...pipeArgs);
            } else {
                return pipe.transform(value, pipeArgs);
            }
        }
        else {
            return value;
        }
    }
}
0
Shawn