【问题标题】:How to use observable value in to an angular pipe?如何在角管中使用可观察值?
【发布时间】:2019-07-29 21:36:49
【问题描述】:

我需要等待一个可观察的值,该值具有我的登录用户在我制作的自定义日期管道中执行“转换”方法的语言。问题是,当从服务器返回用户信息时,来自 mi 应用程序的几个日期会在没有正确语言的情况下使用管道呈现,结果应用程序显示不需要的日期格式。下一个代码示例解决了这个问题,但这是一个不好的做法。有没有办法使用 observables 功能做到这一点?

import {
    Injector,
    Pipe,
    PipeTransform
} from '@angular/core';
import { CurrentUserService } from '@lib/app-npm-base';
@Pipe({
    name: 'customDate'
})
export class CustomDatePipe implements PipeTransform {
    lang = '';

    public constructor(
        private readonly injector: Injector, 
        private readonly 
        userService: CurrentUserService
    ) {
        this.lang = this.getLang();
    }
    async getLang(): string {
        return (await this.userService.getCurrentUserPreferredLanguage().toPromise()).language;
    }
    transform(
        value: Date | null | undefined,
        lang: string | null | undefined,
        options: Intl.DateTimeFormatOptions = {
            day: '2-digit',
            month: '2-digit',
            year: 'numeric'
        },
        isTime = false
    ): string {
        if(value === null || value === undefined) {
            return '';
        }
        let localLan = lang === null || lang === undefined ? this.lang : lang;
        let format = isTime ? value.toLocaleTimeString(localLan, options) : value.toLocaleDateString(localLan, options);
        return format;
    }
}

如您所见,我使用 async 方法返回转换为“Promise”的“Observable”的 await,然后我在构造函数上调用该方法我得到了想要的结果。

更新 01

使用Alex 描述的方法,我想到了将 AsincPipe 注入我的 CustomDatePipe 并调用 AsincPipe 转换方法我的 Observable 作为参数。

....
    public constructor(
        private readonly injector: Injector,
        protected readonly userService: CurrentUserService,
        private readonly async: AsyncPipe
    ) {
        // Empty
    }
    transform(
        value: Date | null | undefined,
        lang: string | null | undefined,
        options: Intl.DateTimeFormatOptions = {
            day: '2-digit',
            month: '2-digit',
            year: 'numeric'
        },
        isTime = false
    ): string {
        return this.async.transform(this.userService.getCurrentUserPreferredLanguage().pipe(map((preferredLanguage: PreferredLanguage) => {
            if(value === null || value === undefined) {
                return '';
            }
            let localLan = lang === null || lang === undefined ? preferredLanguage.language : lang;
            let format = isTime ? value.toLocaleTimeString(localLan, options) : value.toLocaleDateString(localLan, options);
            return format;
        })));
    }
}

然后在我的模块中:

....
@NgModule({
    declarations: [
        CustomDatePipe,
        ....
    ],
    exports: [
        CustomDatePipe,
        .....
    ],
    providers: [
        AsyncPipe,
        ChangeDetectorRef as Provider,
        CustomDatePipe,
        .....
    ]
})
....

这是一种更好的方法并且仍然有效,但我现在在控制台上收到 ERROR TypeError: this._ref.markForCheck is not a function 错误。发生错误是因为 this._ref 在 'common.js' 中没有方法 markForCheck()。这可能是什么原因?

【问题讨论】:

    标签: angular pipe observable


    【解决方案1】:

    您可以通过返回 Observable 使您的转换函数直接异步。然后,您的管道将与模板中的异步管道一起使用

    import {
        Injector,
        Pipe,
        PipeTransform
    } from '@angular/core';
    import { CurrentUserService } from '@lib/app-npm-base';
    @Pipe({
        name: 'customDate'
    })
    export class CustomDatePipe implements PipeTransform {
        lang = '';
    
        public constructor(
            private readonly injector: Injector, 
            private readonly 
            userService: CurrentUserService
        ) {}
    
        transform(
            value: Date | null | undefined,
            lang: string | null | undefined,
            options: Intl.DateTimeFormatOptions = {
                day: '2-digit',
                month: '2-digit',
                year: 'numeric'
            },
            isTime = false
        ): Observable<string> {
            return Observable.create(observer => {
              this.userService.getCurrentUserPreferredLanguage()
              .subscribe(langInfo => {
                const fetchedLang = langInfo.language;
                if(value === null || value === undefined) {
                    return '';
                }
                let localLan = lang || fetchedLang;
                let format = isTime ? value.toLocaleTimeString(localLan, options) : value.toLocaleDateString(localLan, options);
                observer.next(format);
                observer.complete();
              });
            });
    
        }
    }
    
    {{ date | async | customDate }}
    

    【讨论】:

    • 还有其他方法吗?因为这会让我更新我所有的观点,我只需要一次获得语言
    • 另一种方法是在引导程序上设置您的 LOCALE_ID 令牌,并在您的管道中同步使用它angular.io/api/core/LOCALE_ID
    • 但我仍然需要服务中的值,因为我从端点获取用户语言
    • 您可以在 main.ts 文件中从您的端点设置它,这里是一个示例:``` fetch(cultureEndpoint) .then((res) => res.body) .then(( stream) => { const reader = stream.getReader(); reader.read().then(({done, value}) => { const decoded = new TextDecoder('utf-8').decode(value); const parsed = JSON.parse(decoded); constculture = parsed.data.culture; platformBrowserDynamic([{ 提供: LOCALE_ID, useValue:culture.code }]).bootstrapModule(AppModule); }); }); ```
    • 最后我会将这个标记为答案,因为它是 Angular 中最合适的方法,但我仍然不喜欢 Angular 让我这样做的方式,因为我正在制作一个返回 Observable 的管道,这使得有义务与管道使用异步,并使其依赖:(
    猜你喜欢
    • 2017-05-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多