带有可观察到的异步管道问题的角度模板绑定 [英] Angular template binding with Observable async pipe issue

查看:98
本文介绍了带有可观察到的异步管道问题的角度模板绑定的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

注意,我在模板:

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

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

The problem is the the decorator is called multiple times:

如果转到该分支:

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

then it keep sending requests to the backend servcie and the binding never output anything:

如果它是异步可观察者,它似乎将一直尝试评估可观察者而不会结束,请说一句:

It looks like it will always keep trying evaluate the observable without ending if it is an async obserable, say this one:

更新2020年5月14日

我从具有功能的模板绑定中得到了答案返回可观察和异步管道

最后,我将方法装饰器"更改为属性装饰器"并修复问题.

In the end I changed the Method Decorator to Property Decorator and issue fixed.

推荐答案

当您使用insuredType$() | async之类的东西时,它意味着每当进行更改检测时,angular都会调用此函数.因此它每次也会调用needsDefApi.fetchOne(productId, elementId).

when you use things like insuredType$() | async it means that angular will call this function every time when change detection is happening. therefore it calls needsDefApi.fetchOne(productId, elementId) every time too.

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

To avoid it you need to mark your component OnPush. What is actually a lifehack to reduce amount of calls, because it will be called only in case of changed inputs or triggered outputs of the component. If it happens often - it won't help.

或者您需要重组装饰器,以在对相同entity的任何调用上返回相同的Observable,因此entity?.ext.insuredDetails.insuredType$() === entity?.ext.insuredDetails.insuredType$()为真.

Or you need to restructure the decorator to return the same Observable on any call for the same entity so entity?.ext.insuredDetails.insuredType$() === entity?.ext.insuredDetails.insuredType$() would be true.

不确定是否可以使用,但应该与之类似:

Not sure if it works but it should be similar to it:

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

这篇关于带有可观察到的异步管道问题的角度模板绑定的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆