注意我在模板绑定中使用函数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] 删除。
我来说两句