Угловой - Используйте трубы в сервисах и компонентах

331

В AngularJS я могу использовать фильтры (каналы) внутри сервисов и контроллеров, используя синтаксис, подобный следующему:

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

Можно ли использовать каналы в сервисах / компонентах, подобных этому в Angular?

POSIX-совместимый
источник
1
для Angular 8 Проверьте этот учебник по встроенным и пользовательским каналам freakyjolly.com/angular-8-pipes-all-type-of-pipes-with-examples
Code Spy

Ответы:

660

Как обычно в Angular, вы можете положиться на внедрение зависимостей:

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

class MyService {

  constructor(private datePipe: DatePipe) {}

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

Добавить DatePipeв список поставщиков в вашем модуле; если вы забудете сделать это, вы получите ошибку no provider for DatePipe:

providers: [DatePipe,...]

Обновление Angular 6 : Angular 6 теперь предлагает практически все функции форматирования, используемые конвейерами публично. Например, теперь вы можете использовать formatDateфункцию напрямую.

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

class MyService {

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

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

ДоDatePipe версии Angular 5 : Имейте в виду, что до версии 5 использовался API-интерфейс Intl, который поддерживается не всеми браузерами (см. Таблицу совместимости ).

Если вы используете более старые версии Angular, вы должны добавить Intlполифилл в ваш проект, чтобы избежать каких-либо проблем. Смотрите этот связанный вопрос для более подробного ответа.

cexbrayat
источник
Каков будет результат использования DatePipe в браузере, который не поддерживает Intl? Существует ли какой-либо тип прокладки / уловки, чтобы противостоять отсутствию поддержки?
POSIX-совместимый
К сожалению, это приведет к ошибке и сломает ваше приложение прямо сейчас. Есть проблемы, открытые на трекере Github, но похоже, что в настоящее время нет хорошего polyfill ...
cexbrayat
4
Это не работает для пользовательских каналов, которые сами используют внедрение зависимостей в своем конструкторе. Или я ошибаюсь?
Мюррей Смит
1
@JayChase находится в "angular2 / common".
valter.santos.matos
5
@JayChase импортировать и добавлять в разделы поставщика компонентов: `` `import {DatePipe} from '@ angular / common'; @Component ({... provider: [..., DatePipe]}) `` `
alx lark
74

Этот ответ устарел

рекомендую использовать подход DI из других ответов вместо этого подхода

Оригинальный ответ:

Вы должны быть в состоянии использовать класс напрямую

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

Например

var raw = new Date(2015, 1, 12);
var formatted = new DatePipe().transform(raw, 'yyyy-MM-dd');
expect(formatted).toEqual('2015-02-12');
SnareChops
источник
2
При использовании Dateконструктора javascript используются месяцы 0. Так 0же январь и 1февраль. Исправлено пропажаy
SnareChops
24
В случае, если это поможет кому-либо еще, конвейер даты импортирован из 'angular2 / common'.
POSIX-совместимый
1
Фрагмент кода не компилируется .... error TS2345: Argument of type 'string[]' is not assignable to parameter of type 'string'. он-лайнvar formatted = new DatePipe().transform(raw, ['yyyy-MM-dd']);
Пол Горбас
10
Сейчас выпущен Angular v2.0.0, и вы можете внедрить этот канал. Сначала добавьте в NgModule:, @NgModule({ providers:[DatePipe] })затем в своем классе импортируйте и constructor( private datePipe: DatePipe ){}
внедрите
2
тем временем Angular2 DatePipe ожидает Locale_ID в качестве аргумента конструктора. Поэтому, если вы попытаетесь использовать его напрямую, вам придется предоставить исправление Locale_ID, и поэтому оно больше не будет использовать приложения Locale_ID. Вот почему я бы не рекомендовал идти по этому пути.
Э. Хейн
17

Да, это возможно с помощью простой пользовательской трубы. Преимущество использования пользовательского канала заключается в том, что если нам нужно обновить формат даты в будущем, мы можем пойти и обновить один файл.

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

Вы всегда можете использовать эту трубу где угодно, компонент, услуги и т. Д.

Например

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

Не забудьте импортировать зависимости.

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

Примеры пользовательских труб и дополнительная информация

Prashobh
источник
1
Это не отвечает на вопрос о том, как использовать каналы в компоненте или сервисе.
POSIX-совместимый
2
Я уберу свое понижение, если вы обновите свой ответ, чтобы не включать информацию о том, как создавать каналы. Вопрос не имеет ничего общего с тем, как их создавать.
POSIX-совместимый
2
@ POSIX-совместимый Как я уже упоминал в своем ответе, его можно очень легко использовать и обновлять с помощью специального канала. Это может помочь полностью кому-то еще. Голоса второстепенны.
Prashobh
1
Это справедливо, хотя я все еще думаю, что имеет смысл, по крайней мере, сначала получить ту часть, которая отвечает на этот конкретный вопрос. Снятие голосования. Спасибо за ответ и ответ.
POSIX-совместимый
1
Почему вы жестко закодировали "en-US"? Вы не должны вводить как-то?
Герман,
15

Другие ответы не работают в угловых 5?

Я получил ошибку, потому что DatePipe не является провайдером, поэтому его нельзя ввести. Одно из решений заключается в том, чтобы добавить его в качестве поставщика в модуль приложения, но я предпочел создать его экземпляр.

Создайте его там, где это необходимо:

Я посмотрел на исходный код DatePipe, чтобы увидеть, как он получил локаль: https://github.com/angular/angular/blob/5.2.5/packages/common/src/pipes/date_pipe.ts#L15-L174

Я хотел использовать его в трубе, поэтому мой пример в другой трубе:

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

Ключевым моментом здесь является импорт Inject и LOCALE_ID из ядра angular, а затем инъекция, чтобы вы могли передать его DatePipe для его правильной реализации.

Сделать DatePipe провайдером

В вашем модуле приложения вы также можете добавить DatePipe в ваш массив провайдеров следующим образом:

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

@NgModule({
    providers: [
        DatePipe
    ]
})

Теперь вы можете просто вставить его в ваш конструктор, где это необходимо (как в ответе cexbrayat).

Резюме:

Любое решение сработало, я не знаю, какой из угловых будет считать наиболее «правильным», но я решил создать его вручную, поскольку angular не предоставлял datepipe в качестве самого провайдера.

csga5000
источник
3
Вы можете сделать это также для каждого поставщика компонентов
Джимми Кейн
Спасибо, ваш ответ самый исчерпывающий. Я ищу некоторые ресурсы о различиях между созданием канала с новым или зависимостью, его непосредственным добавлением и добавлением в провайдеры, и я ничего не могу найти. Я предпочитаю 2-й подход, потому что, когда вы newподнимаетесь по трубе, вам все равно придется DI локали. Я нахожу весь @Inject(LOCALE_ID) private locale: stringсинтаксис громоздким.
codeepic
@ codeepic Я бы, наверное, не сказал, что есть огромная разница. Если вы спросите меня, возможно, Angular должен был сделать это провайдером.
csga5000
9

Если вы не хотите делать 'new myPipe ()', потому что вы вводите зависимости в pipe, вы можете внедрить в компонент, такой как поставщик, и использовать без нового.

Пример:

// 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);
  }
}
Энди
источник
9

Если вы хотите использовать свой собственный канал в ваших компонентах, вы можете добавить

@Injectable({
  providedIn: 'root'
})

аннотация к вашей заказной трубе. Затем вы можете использовать его в качестве службы

SRT
источник
это хорошо иметь providedIn: 'root'внутри нашей трубы или в местном модуле, где используется труба?
Daniel.V
1
Это зависит от того, где вы используете трубу. Если вы используете трубу только в одном модуле, вы можете выбрать второй вариант. Но если вы используете канал в нескольких модулях в вашем приложении, вы должны выбрать первый вариант, который предоставляется в: 'root'
srt
8

Начиная с Angular 6 вы можете импортировать formatDateиз @angular/commonутилиты для использования внутри компонентов.

Это было внедрено в https://github.com/smdunn/angular/commit/3adeb0d96344c15201f7f1a0fae7e533a408e4ae

Я могу быть использован как:

import {formatDate} from '@angular/common';
formatDate(new Date(), 'd MMM yy HH:mm', 'en');

Хотя локаль должна быть предоставлена

Джимми Кейн
источник
5

Вы можете использовать formatDate () для форматирования даты в службах или компонентах ts. синтаксис:-

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

импортировать formatDate () из общего модуля, как это,

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

и просто использовать его в классе, как это,

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

Вы также можете использовать предопределенные параметры формата, предоставляемые angular, как это,

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

Вы можете увидеть все другие предопределенные параметры формата здесь,

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

Сксаиф Уддин
источник