带有可观察到的异步管道问题的角度模板绑定

Gelin Luo

注意我在模板绑定中使用函数return Observable和async pipe创建了此问题的简化版本

模板:

<div *ngIf="entity?.ext.insuredDetails.insuredType$() | async as insuredType">
 {{insuredType}}
</div>

insuredType$ 定义:

@NeedsElement(sp(115621),ap(116215))
insuredType$(): Observable<string> {
  return empty();
}

NeedsElement 装饰者:

export function NeedsElement(...mappings: NeedsElementMapping[]) {
  if (mappings.length === 0) {
    throw new Error('needs mapping expected');
  }

  let lookup = new Map<ProductId, number>();
  mappings.forEach((mapping) => {
    lookup.set(mapping.productId, mapping.elementId);
  });

  return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {
    descriptor.value = function (...args: any[]) {
      Logger.info("bbbbb");
      let entity = UcEntityStoreContext.currentEntity;
      let productId = entity['productId'];
      if (!productId) {
        throw new Error(`Cannot get product Id from host entity: ${entity.ucId}`);
      }
      let elementId: number = lookup.get(entity['productId']);
      if (!elementId) {
        throw new Error(`Cannot locate needs element ID by productId ${productId}`);
      };
      let enitityStore = UcEntityStoreContext.current;
      let entityApi = enitityStore.apiService as QuotePolicyApiBase<any>;
      let needsDefApi = NeedsDefinitionApi.instance;

      return needsDefApi.fetchOne(productId, elementId).pipe(
        concatMap(
          nd => {
            return entityApi.fetchNeedsElementValue(entity.ucId, elementId).pipe(
              concatMap(needsVal => {
                if (!needsVal) {
                  return of("");
                }
                if (nd.lookupId) {
                  return LookupApi.instance.getByPrimaryValueId(nd.lookupId, needsVal).pipe(
                    map(res => res.primaryValue)
                  );
                } else {
                  return of(needsVal);
                }
              })
            )
          }
        )
      );
    };
  };
}

问题是装饰器被多次调用:

在此处输入图片说明

如果转到该分支:

在此处输入图片说明

然后它将继续向后端服务发送请求,并且绑定永远不会输出任何内容:

在此处输入图片说明

如果它是异步可观察者,它似乎将一直尝试评估可观察者而不会结束,请说一句: 在此处输入图片说明


更新14 / May / 2020

我从模板绑定得到了答案,该函数具有函数return Observable和async pipe

最后,我将“方法装饰器”更改为“属性装饰器”,并已解决问题。

萨坦时间

当您使用类似insuredType$() | async功能时,这意味着每次发生更改检测时,angular都会调用此函数。因此它needsDefApi.fetchOne(productId, elementId)也会每次调用

为了避免这种情况,您需要标记组件OnPush实际上,这是减少调用数量的救生衣,因为只有在组件的输入更改或触发输出的情况下才会调用该控件。如果经常发生-这将无济于事。

或者您需要重组装饰器以Observable在任何调用中返回相同的装饰物,entity因此entity?.ext.insuredDetails.insuredType$() === entity?.ext.insuredDetails.insuredType$()这是正确的。

不知道它是否有效,但应该与之相似:

export function NeedsElement(...mappings: NeedsElementMapping[]) {
    if (mappings.length === 0) {
        throw new Error('needs mapping expected');
    }

    let lookup = new Map<ProductId, number>();
    mappings.forEach((mapping) => {
        lookup.set(mapping.productId, mapping.elementId);
    });

    Logger.info("bbbbb");
    let entity = UcEntityStoreContext.currentEntity;
    let productId = entity['productId'];
    if (!productId) {
        throw new Error(`Cannot get product Id from host entity: ${entity.ucId}`);
    }
    let elementId: number = lookup.get(entity['productId']);
    if (!elementId) {
        throw new Error(`Cannot locate needs element ID by productId ${productId}`);
    };
    let enitityStore = UcEntityStoreContext.current;
    let entityApi = enitityStore.apiService as QuotePolicyApiBase<any>;
    let needsDefApi = NeedsDefinitionApi.instance;

    const stream$ = needsDefApi.fetchOne(productId, elementId).pipe(
        concatMap(
            nd => {
                return entityApi.fetchNeedsElementValue(entity.ucId, elementId).pipe(
                    concatMap(needsVal => {
                        if (!needsVal) {
                            return of("");
                        }
                        if (nd.lookupId) {
                            return LookupApi.instance.getByPrimaryValueId(nd.lookupId, needsVal).pipe(
                                map(res => res.primaryValue)
                            );
                        } else {
                            return of(needsVal);
                        }
                    })
                )
            }
        )
    );

    return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {
        descriptor.value = function (...args: any[]) {
            return stream$; // <- returns the same stream every time.
        };
    };
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章