Angular - Use tubos em serviços e componentes

331

No AngularJS, eu posso usar filtros (pipes) dentro de serviços e controladores usando uma sintaxe semelhante a esta:

$filter('date')(myDate, 'yyyy-MM-dd');

É possível usar tubos em serviços / componentes como este no Angular?

Compatível com POSIX
fonte
1
para Angular 8 Verifique este tutorial sobre embutido e personalizado Tubos freakyjolly.com/angular-8-pipes-all-type-of-pipes-with-examples
Code Spy

Respostas:

660

Como de costume no Angular, você pode confiar na injeção de dependência:

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

class MyService {

  constructor(private datePipe: DatePipe) {}

  transformDate(date) {
    return this.datePipe.transform(date, 'yyyy-MM-dd');
  }
}

Adicione DatePipeà sua lista de provedores em seu módulo; se você esquecer de fazer isso, receberá um erro no provider for DatePipe:

providers: [DatePipe,...]

Atualizar o Angular 6 : O Angular 6 agora oferece praticamente todas as funções de formatação usadas pelos canais publicamente. Por exemplo, agora você pode usar a formatDatefunção diretamente.

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

class MyService {

  constructor(@Inject(LOCALE_ID) private locale: string) {}

  transformDate(date) {
    return formatDate(date, 'yyyy-MM-dd', this.locale);
  }
}

Antes do Angular 5 : esteja avisado, porém, de que ele DatePipeestava confiando na API Intl até a versão 5, que não é suportada por todos os navegadores (verifique a tabela de compatibilidade ).

Se você estiver usando versões angulares mais antigas, adicione o Intlpolyfill ao seu projeto para evitar qualquer problema. Veja esta pergunta relacionada para uma resposta mais detalhada.

cexbrayat
fonte
Qual seria o resultado do uso do DatePipe em um navegador que não suporta Intl? Existe algum tipo de calço / manuseio disponível para combater a falta de suporte?
acordo com POSIX
Infelizmente, isso gera um erro e interrompe seu aplicativo no momento. Há questões abertas sobre o rastreador Github, mas parece que não há atualmente nenhuma boa polyfill ...
cexbrayat
4
Isso não parece funcionar para tubos personalizados que usam injeção de dependência em seus construtores. Ou estou enganado?
Murray Smith
1
@JayChase está em "angular2 / common".
Valter.santos.matos 5/05
5
@JayChase importe e adicione seções do provedor de componentes: `` `import {DatePipe} from '@ angular / common'; @Component ({... provider: [..., DatePipe]}) `` `
alx lark
74

Esta resposta está desatualizada

recomendamos o uso da abordagem DI de outras respostas, em vez desta abordagem

Resposta original:

Você deve poder usar a classe diretamente

new DatePipe().transform(myDate, 'yyyy-MM-dd');

Por exemplo

var raw = new Date(2015, 1, 12);
var formatted = new DatePipe().transform(raw, 'yyyy-MM-dd');
expect(formatted).toEqual('2015-02-12');
SnareChops
fonte
2
Ao usar o Dateconstrutor javascript , os meses são 0baseados. Assim 0é janeiro e 1fevereiro. Correção ausentey
SnareChops 02/02
24
No caso de ajudar qualquer outra pessoa, o pipe de data é importado do 'angular2 / common'.
acordo com POSIX
1
O trecho de código não compilar .... error TS2345: Argument of type 'string[]' is not assignable to parameter of type 'string'. on-linevar formatted = new DatePipe().transform(raw, ['yyyy-MM-dd']);
Paul Gorbas
10
Agora lançou o Angular v2.0.0, e você pode injetar esse tubo. Primeiro, adicione a NgModule: @NgModule({ providers:[DatePipe] }), em seguida, em sua classe, importação e injetar constructor( private datePipe: DatePipe ){}
ktretyak
2
enquanto isso, o Angular2 DatePipe espera o Locale_ID como argumento do construtor. Portanto, se você tentar usá-lo diretamente, precisará fornecer um Locale_ID fixo e, portanto, não precisará mais dos aplicativos Locale_ID. É por isso que eu NÃO recomendaria seguir esse caminho.
E. Hein
17

Sim, é possível usando um pipe personalizado simples. A vantagem de usar canal personalizado é que, se precisarmos atualizar o formato da data no futuro, podemos atualizar um único arquivo.

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

@Pipe({
    name: 'dateFormatPipe',
})
export class dateFormatPipe implements PipeTransform {
    transform(value: string) {
       var datePipe = new DatePipe("en-US");
        value = datePipe.transform(value, 'MMM-dd-yyyy');
        return value;
    }
}

{{currentDate | dateFormatPipe }}

Você sempre pode usar este canal em qualquer lugar, componente, serviços etc.

Por exemplo

export class AppComponent {
  currentDate : any;
  newDate : any;
  constructor(){
    this.currentDate = new Date().getTime();
    let dateFormatPipeFilter = new dateFormatPipe();
    this.newDate = dateFormatPipeFilter.transform(this.currentDate);
    console.log(this.newDate);
}

Não se esqueça de importar dependências.

import { Component } from '@angular/core';
import {dateFormatPipe} from './pipes'

Exemplos de tubos personalizados e mais informações

Prashobh
fonte
1
Isso não responde à pergunta de como usar tubos em um componente ou serviço.
em conformidade com POSIX
2
Removerei meu voto negativo se você atualizar sua resposta para não incluir informações sobre como criar tubos. A questão não tem nada a ver com como criá-los.
Compatível com POSIX
2
@ Compatível com POSIX Como mencionei na minha resposta, ele pode reutilizar e atualizar com muita facilidade usando o pipe personalizado. Pode ajudar bastante para outra pessoa. Os votos são secundários.
Prashobh
1
Esse é um argumento justo, embora eu ainda pense que faz sentido ter pelo menos a parte que responde a essa pergunta específica primeiro. Removendo votação inativa. Obrigado pela resposta e resposta.
POSIX-compliant
1
Por que você codificou "en-US"? Você não deve injetar de alguma forma?
Gherman
15

Outras respostas não funcionam no angular 5?

Recebi um erro porque o DatePipe não é um provedor, portanto não pode ser injetado. Uma solução é colocá-lo como um provedor no seu módulo de aplicativo, mas minha solução preferida foi instancia-lo.

Instancie-o quando necessário:

Eu olhei para o código-fonte do DatePipe para ver como ele conseguiu o código do idioma: https://github.com/angular/angular/blob/5.2.5/packages/common/src/pipes/date_pipe.ts#L15-L174

Eu queria usá-lo dentro de um pipe, então meu exemplo está dentro de outro pipe:

import { Pipe, PipeTransform, Inject, LOCALE_ID } from '@angular/core';
import { DatePipe } from '@angular/common';

@Pipe({
    name: 'when',
})
export class WhenPipe implements PipeTransform {
    static today = new Date((new Date).toDateString().split(' ').slice(1).join(' '));
    datePipe: DatePipe;

    constructor(@Inject(LOCALE_ID) private locale: string) {
        this.datePipe = new DatePipe(locale);
    }
    transform(value: string | Date): string {
        if (typeof(value) === 'string')
            value = new Date(value);

        return this.datePipe.transform(value, value < WhenPipe.today ? 'MMM d': 'shortTime')
    }
}

A chave aqui é importar Inject e LOCALE_ID do núcleo da angular e, em seguida, injetar isso para que você possa fornecê-lo ao DatePipe para instancia-lo corretamente.

Tornar o DatePipe um provedor

No seu módulo de aplicativo, você também pode adicionar o DatePipe à sua matriz de provedores assim:

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

@NgModule({
    providers: [
        DatePipe
    ]
})

Agora você pode injetá-lo no seu construtor sempre que necessário (como na resposta do cexbrayat).

Resumo:

Qualquer uma das soluções funcionou, não sei qual angular consideraria a mais "correta", mas optei por instanciar manualmente, pois a angular não fornecia o datepipe como um provedor.

csga5000
fonte
3
Você pode fazê-lo também por provedor componente
Jimmy Kane
Obrigado, sua resposta é a mais exaustiva. Estou procurando alguns recursos sobre as diferenças entre instanciar o canal com novo ou dependência, injetando-o diretamente e adicioná-lo aos provedores e não consigo encontrar nada. Eu prefiro a segunda abordagem, porque quando você newaprova o pipe, você ainda precisa identificar o local. Acho toda a @Inject(LOCALE_ID) private locale: stringsintaxe complicada.
Codepic
@ codeepic Eu provavelmente não diria que há uma enorme diferença realmente. Se você me perguntar, angular provavelmente deveria ter feito disso um provedor.
csga5000
9

Se você não deseja fazer 'new myPipe ()' porque está injetando dependências no canal, é possível injetar componentes como provedor e usá-los sem novos.

Exemplo:

// In your component...

import { Component, OnInit } from '@angular/core';
import { myPipe} from './pipes';

@Component({
  selector: 'my-component',
  template: '{{ data }}',
  providers: [ myPipe ]
})
export class MyComponent() implements OnInit {
  data = 'some data';
  constructor(private myPipe: myPipe) {}

  ngOnInit() {
    this.data = this.myPipe.transform(this.data);
  }
}
andy
fonte
9

Se você quiser usar seu pipe personalizado em seus componentes, poderá adicionar

@Injectable({
  providedIn: 'root'
})

anotação no seu pipe personalizado. Em seguida, você pode usá-lo como um serviço

srt
fonte
é bom ter providedIn: 'root'dentro do tubo ou fornecido em um módulo local onde o tubo é usado?
Daniel.V
1
Depende de onde você usa o tubo. Se você usar o tubo em apenas um módulo, poderá selecionar a segunda opção. Mas se você usar o canal em vários módulos em seu aplicativo, deverá selecionar a primeira opção que é fornecida. In: 'root'
srt
5

Você pode usar formatDate () para formatar a data nos serviços ou no componente ts. sintaxe:-

formatDate(value: string | number | Date, format: string, locale: string, timezone?: string): string

importe o formatDate () do módulo comum como este,

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

e apenas use-o na classe assim,

formatDate(new Date(), 'MMMM dd yyyy', 'en');

Você também pode usar as opções de formato predefinidas fornecidas pelo angular como este,

formatDate(new Date(), 'shortDate', 'en');

Você pode ver todas as outras opções de formato predefinidas aqui,

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

Sksaif Uddin
fonte