Angular-如何将管道注入指令

时间:2018-09-15 09:45:35

标签: angular

我设置了一个指令,该指令根据您作为参数传递的管道(@Input)将格式赋予输入值。我将其用于反应形式。

为此,我需要导入所有所需的管道(现在是一个),并提供一个开关以使用正确的管道。

我的问题是:是否有一种方法可以从喷射器获取任何管道,而只需知道其令牌,例如const pipe = injector.get(‘currency’)

这是我的指令代码:

import { Input, Renderer2, ElementRef, forwardRef, Directive, HostListener } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { CurrencyPipe } from '@angular/common';

@Directive({
    selector: '[formatInput]',
    providers: [
        { provide: NG_VALUE_ACCESSOR, multi: true, useExisting: forwardRef(() => FormatInputDirective) },
    ],
})
export class FormatInputDirective implements ControlValueAccessor {
    private changeCallback: Function;
    private touchedCallback: Function;

    @Input() pipe: any; // { token: string, args: any[] }

    @HostListener('input', ['$event.target.value'])
    onChange(value) {
        this.changeCallback(value);
    }

    @HostListener('blur', ['$event.target'])
    onBlur(target) {
        this.touchedCallback();
    }

    constructor(private renderer: Renderer2, private currency: CurrencyPipe, private elRef: ElementRef ) {
        this.changeCallback = (_: any) => {};
        this.touchedCallback = () => {};
    }

    writeValue(value: any): void {
        this.renderer.setProperty(this.elRef.nativeElement, 'value', this.setPipedValue(value));
    }

    setPipedValue(value: any): any {
        if (!this.pipe || !value) {
            return value;
        } else {
            let pipe;

            switch (this.pipe.token) {
                case 'currency':
                    pipe = this.currency;
                    break;
            }
            return pipe.transform(value, ...this.pipe.args);
        }
    }

    registerOnChange(fn) {
        this.changeCallback = fn;
    }

    registerOnTouched(fn: any): void {
        this.touchedCallback = fn;
    }
}

预先感谢您的答复。

2 个答案:

答案 0 :(得分:2)

与注射一样,您首先必须提供要使用的东西。 在相应的NgModule中,将CurrencyPipe(以及以后要注入的所有其他元素)添加到providers的数组中。

providers: [CurrencyPipe],

现在通过将Injector添加到指令的构造函数中来注入它。

constructor (private injector: Injector)

通过使用get方法和令牌作为参数,使用它来捕获所需管道的实例。在这种情况下,令牌是类本身。

const pipe = injector.get(CurrencyPipe)

现在您有一个管道实例。 您可以使用其transform方法执行转换。

this.value = pipe.transform(123456789)

您可以see this in action on StackBlitz

请注意,Angular没有使用字符串进行依赖项注入的概念。您可以改用令牌,但是在使用管道的情况下,这并不能给您提供很多强大的功能。

如果要将管道指定为字符串,则必须自己定义映射。

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

现在使用此映射来生成正确管道的实例。

const pipeName = 'currency'
const pipeClass = MAP[pipeName]
const pipe = injector.get(pipeClass)
const value = pipe.transform(input)

答案 1 :(得分:1)

在角度6中,过滤器方法也直接从@angular/common包中导出,例如:

import { formatCurrency } from '@angular/common';

https://angular.io/api/common/formatCurrency

或者您可以自己直接实例化管道,而无需使用DI,因为它是简单的帮助程序类,没有任何依赖关系:

import { CurrencyPipe } from '@angular/common';

const pipe = new CurrencyPipe('en-US');
pipe.transform(...);