我在组件文件中定义了一个Observable
。当使用双curlys({{example}}
)进行插值时,它会相应地更新。但是,即使我使用的是async
管道,它也不会在template指令中更新。component.html
<ng-container *ngIf="isLoading$ | async as isLoading; else elseBlock">
is loading
</ng-container>
<ng-template #elseBlock> Add</ng-template> <--- constantly showing elseblock; not working!
is loading: {{ isLoading$ | async }} <--- is working correctly
component.ts
updateIsLoading: any;
isLoading$ = new Observable((observer) => {
observer.next(false);
this.updateIsLoading = function (newValue: boolean) {
observer.next(newValue);
observer.complete();
};
});
handleClick() {
this.updateIsLoading(true); <--- running this line updates interpolated value, but not the if statement
}
编辑
显然,注解掉第二个async
会使第一个行为适当。
4条答案
按热度按时间tuwxkamq1#
这只是对
async
管道和/或可观测量的误解。isLoading$ | async
的每个示例创建一个“单独”的订阅。此订阅将执行回调函数,用新函数覆盖
this.updateIsLoading
。所以你的点击处理程序只会为最后一个
isLoading$ | async
订阅触发observer.next(newValue)
。理想情况下,您只需要调用
isLoading$ | async
一次,并将其放入模板变量中。不幸的是,Angular没有一个内置的指令来声明一个模板变量,尽管你可以自己编写,也有一些包,比如
ng-let
。可以用
as
Package*ngIf
中的所有内容以获得一个模板变量,但是如果您想允许falsey值通过,那么这是行不通的。你可以使用
ng-template
let-*
语法来实现它,其思想是定义一个模板,并通过ngTemplateOutletContext
将异步变量作为参数传入,实际的渲染是由ng-container
完成的。堆栈 lightning 战:https://stackblitz.com/edit/angular-x4msbz?file=src/main.html
或者,你可以像Sergey建议的那样,将可观察性转化为一个共享流,这将允许你进行任意数量的订阅,所有订阅共享相同的值,这取决于你的用例。
m3eecexj2#
答案有点简单,同时也有点见不得人。这里有一个小提示:
Created
将在控制台中被记录两次,所以每次在Observable上调用| async
时,传递给构造函数的函数都会被执行,updateIsLoading
会被覆盖,所以只有最后一个|async
绑定在工作。因此,如果您希望有2个
async
管道-请使用Subject
。注意:Subject中没有初始值,因此在
is loading: (value)
中该值将为空字符串。或者您可以使用
share()
运算符:会像“预期的”那样工作。
其他详细信息:What is the difference between Observable and a Subject in rxjs?
3ks5zfa03#
as
是一个Angular 关键字,使用它可以将async
管道的结果赋给其他变量。{{ isLoading$ | async }}
现在是模板中的变量isLoading
。将其用作:
qgzx9mmu4#
这可能是一个不受欢迎的答案,但我更喜欢保持模板非常简单,并把任何必要的复杂性放在组件中,在组件中可以获得ts/js的完整表达能力。
在这种情况下,我认为在组件中订阅会更容易/更容易理解/更容易维护,并在不影响订阅的情况下更新一个可以在模板中轻松多次使用的属性。
恕我直言,异步管道只是不必要地复杂化这里的事情。
TLDR:保持模板简单,保持它们的逻辑简单。