在RxJS中重新使用可管道操作符

在RxJS中重新使用可管道操作符,rxjs,Rxjs,我在Angular组件中有两个主题,它们利用相同的一组可管道操作符为两个不同的表单字段提供提前键入搜索查找。例如: this.codeSearchResults$ = this.codeInput$ .pipe( untilDestroyed(this), distinctUntilChanged(),

我在Angular组件中有两个主题,它们利用相同的一组可管道操作符为两个不同的表单字段提供提前键入搜索查找。例如:

this.codeSearchResults$ = this.codeInput$
                               .pipe(
                                 untilDestroyed(this),
                                 distinctUntilChanged(),
                                 debounceTime(250),
                                 filter(value => value !== null),
                                 switchMap((value: string) => {
                                   const params: IUMLSConceptSearchParams = {
                                     ...TERMINOLOGY_SEARCH_PARAMS,
                                     sabs: this.sabs,
                                     term: value
                                   };

                                   return this.terminologyService.umlsConceptSearch(params);
                                 }),
                               );
似乎它将接受任意数量的函数,但是通过扩展提供函数

this.codeSearchResults$ = this.codeInput$.pipe(...operators);
没有按预期工作。如何为这两个主题提供单一的函数输入源,以保持代码的干燥

编辑 根据Dan Kreiger的回答,我的最终代码如下:

const operations = (context) => pipe(
      untilDestroyed(context),
      distinctUntilChanged(),
      debounceTime(250),
      filter(value => value !== null),
      switchMap(value => {
        const term: string = value as unknown as string;
        const params: IUMLSConceptSearchParams = {
          ...TERMINOLOGY_SEARCH_PARAMS,
          sabs: context.sabs,
          term,
        };

        return context.terminologyService.umlsConceptSearch(params) as IUMLSResult[];
      }),
    );

    this.codeSearchResults$ = this.codeInput$
                                  .pipe(
                                    tap(() => this.codeLookupLoading = true),
                                    operations(this),
                                    tap(() => this.codeLookupLoading = false),
                                  ) as Observable<IUMLSResult[]>;

    this.displaySearchResults$ = this.displayInput$
                                      .pipe(
                                        tap(() => this.displayLookupLoading = true),
                                        operations(this),
                                        tap(() => this.displayLookupLoading = false),
                                      ) as Observable<IUMLSResult[]>;
const operations=(上下文)=>pipe(
不受干扰(上下文),
distinctUntilChanged(),
去BounceTime(250),
过滤器(值=>value!==null),
开关映射(值=>{
常量项:字符串=与字符串一样未知的值;
常量参数:IUMLSConceptSearchParams={
…术语搜索参数,
sabs:context.sabs,
学期
};
将context.terminologyService.umlsConceptSearch(params)作为IUMLSResult[]返回;
}),
);
this.codeSearchResults$=this.codeInput$
.烟斗(
轻触(()=>this.codeLookUpload=true),
运营(本),
轻触(()=>this.codeLookUpload=false),
)可观察的;
this.displaySearchResults$=this.displayInput$
.烟斗(
点击(()=>this.displayLookUpload=true),
运营(本),
轻触(()=>this.displayLookUpload=false),
)可观察的;

我需要编写两个函数,每个主题都是唯一的,它可以按预期工作。

这里有4种可能的方法

1。返回运算符列表的实用函数

如果要在上下文之间重用它,可以尝试创建一个函数,该函数接受
thisArg
,并返回一个运算符数组

然后可以在传递给
管道的参数中扩展调用的函数

/**
 * @param {object} thisArg - context using the typeahead
 * @returns {OperatorFunction[]}
 * 
 * list of pipepable operators 
 * that can have a dynamic `this` context
 */
const typeAhead = thisArg => [
  untilDestroyed(thisArg),
  distinctUntilChanged(),
  debounceTime(250),
  filter(value => value !== null),
  switchMap((value: string) => {
    const params: IUMLSConceptSearchParams = {
      ...TERMINOLOGY_SEARCH_PARAMS,
      sabs: thisArg.sabs,
      term: value
    };

    return thisArg.terminologyService.umlsConceptSearch(params);
  })
]


// subject A
this.codeSearchResults$ = this.codeInput$
  .pipe(...typeAhead(this));

// subject B
this.articleSearchResults$ = this.articleInput$
  .pipe(...typeAhead(this));
注意:
terminologyService
sabs
需要出现在传递给此函数的
上下文中

看起来您正在使用这些组件,因此只要
terminologyService
作为依赖项注入,并且
sabs
是组件的静态成员,它就应该可以工作


2。返回组合运算符的实用函数

或者,您可以通过从
rxjs
导入
pipe
以将操作符链接在一起来实现同样的目的

import { pipe } from "rxjs";

// ... 

const typeAhead = (thisArg) =>
  pipe(
    untilDestroyed(thisArg),
    distinctUntilChanged(),
    debounceTime(250),
    filter((value) => value !== null),
    switchMap((value: string) => {
      const params: IUMLSConceptSearchParams = {
        ...TERMINOLOGY_SEARCH_PARAMS,
        sabs: thisArg.sabs,
        term: value
      };

      return thisArg.terminologyService.umlsConceptSearch(params);
    })
  );
在这种情况下,您不需要使用spread操作符,因为操作符是使用
pipe
的从左到右函数组合组合在一起的

// subject A
this.codeSearchResults$ = this.codeInput$
  .pipe(typeAhead(this));

// subject B
this.articleSearchResults$ = this.articleInput$
  .pipe(typeAhead(this));
注意:
terminologyService
sabs
需要出现在传递给此函数的
上下文中


3。为客户运营商提供的服务

您可以为您的定制管道操作符创建一个可重用的服务。这将允许您从可重用服务本身获取
terminologyService
singleton

但是,看起来无论从何处获得sabs,都需要提供它

如果选择执行此操作,请确保在顶级提供程序中声明
TerminologyService
——请参见示例

然后您可以将其注入到组件中

import { TerminologyService } from "./terminologyService.service";
import { Injectable } from "@angular/core";
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';


@UntilDestroy()
@Injectable({
  providedIn: 'root',
})
export class PipedOperatorsService {
  constructor(private terminologyService: TerminologyService) {}

  typeAhead(thisComponent) {
    return pipe(
      untilDestroyed(thisComponent),
      distinctUntilChanged(),
      debounceTime(250),
      filter((value) => value !== null),
      switchMap((value: string) => {
        const params: IUMLSConceptSearchParams = {
          ...TERMINOLOGY_SEARCH_PARAMS,
          sabs: thisComponent.sabs,
          term: value
        };

        return this.terminologyService.umlsConceptSearch(params);
      })
    );
  }
}
然后您可以在组件中使用它:

从“@angular/core”导入{Component,OnInit};
从“/pipedOperators.service”导入{pipedoperatorservice};
从“rxjs”导入{Observable};
@组成部分({
选择器:“某个根”,
templateUrl:“./some.component.html”,
})
导出类SomeComponent实现OnInit{

sabs=['What'、'is'、'a'、'sab'、'?','谢谢你这么详细的回答,我真的很感激!我不得不做了一些打字,让编译器不要抱怨。我选择了选项2,因为我需要再编写几个运算符。我将把我的最终解决方案添加到我的问题中。我很高兴它有帮助。仅供参考,我刚刚更新了选项4,因为我有如果您选择以后为任何自定义管道操作员提供服务,请删除此
参数: