我觉得问这个有点尴尬,但我肯定我错过了什么。花了很长时间寻找/研究,但只想出复杂而错综复杂的解决方案,需要主题或行为主题或通过合并地图等管道。
在组件超文本标记语言模板中,我将从命令式HTTP可观察方法(手动订阅)转移到反应式HTTP可观察方法(可观察$|async)。
当页面初始化时,使用异步管道工作没有问题。
但是,什么是“动态”刷新模板的最佳方式,即我知道我已将一条记录插入基础数据库,并希望它反映在我的模板中。
使用命令式方法,我可以简单地再次订阅(例如从单击处理程序),并将结果重新分配给与ngfor指令相关联的属性,更改检测将被触发,DOM将被更新。
我想出的唯一解决方案是简单地从服务中再次获取可观察到的,这会触发更改检测。
为了让它更清楚,这里有一系列代码(只关注解决方案非常简单)。
必须有一个简单的解决方案吗?
<div *ngIf="(model$ | async)?.length > 0" class="card mb-3 shadow">
<div class="card-header">Actions Notes</div>
<div class="card-body">
<mat-list *ngFor="let action of model$ | async">
<div class="small">
<strong>
{{action.createdDate | date:'dd/MM/yyyy HH:mm'}}
{{action.createdBy}}
</strong>
</div>
<div>{{action.notes}}</div>
</mat-list>
</div>
</div>
<button (click)="onClick()">name</button>
model$: Observable<any>;
constructor(
private changeTransferActionsService: ChangeTransferActionsService
) {}
ngOnInit(): void {
this.getObservable();
}
private getObservable(): void {
this.model$ = this.changeTransferActionsService
.getActionsWithNotesById(this.model.id)
.pipe(
map((x) => x.result),
share()
);
}
onClick(): void {
//insert row into database here (via HTTP post service call)
this.getObservable();
}
下面是我最初的问题的三个工作解决方案和解释。感谢所有做出回应的人。
使用带有任意类型值和初始值的RxJSBehaviorSubject
。使用展平运算符开关映射
将其与高阶可观测值结合起来。
单击按钮时,Behavior Subject
发出(下一个)一个值(在本例中为0),该值被馈送到HTTP observable(忽略传递值),从而导致内部observable发出一个值并启动更改检测。
当使用行为主体时,可观察对象会在订阅时发出一个值。
在组件超文本标记语言模板中。
<button (click)="onClick()">Click Me</button>
在组件类型脚本中。
import { BehaviorSubject, Observable } from 'rxjs';
.
.
.
subject = new BehaviorSubject(0);
.
.
.
this.model$ = this.subject.asObservable().pipe(
// startWith(0),
switchMap(() => this.changeTransferActionsService
.getActionsWithNotesById(this.model.id)
.pipe(
map((x) => x.result)
)));
.
.
.
onClick(): void {
this.subject.next(0);
}
使用RxJS主题
将此与使用平坦运算符SwitchMap
可观察到的高阶相结合。
单击按钮时,主题
发出(下一个)一个值(本例中未定义),该值被馈送到HTTP observable(忽略传递值),从而导致内部observable发出一个值并启动更改检测。
主体需要一个startWith(0)
,否则当组件首次初始化并通过异步管道首次订阅时,可观察对象将不会发出任何值。
import {Observable, Subject } from 'rxjs';
.
.
.
subject = new Subject();
.
.
.
this.model$ = this.subject.asObservable().pipe(
startWith(0),
switchMap(() => this.changeTransferActionsService
.getActionsWithNotesById(this.model.id)
.pipe(
map((x) => x.result)
)));
.
.
.
onClick(): void {
this.subject.next(0);
}
<button (click)="onClick()">Click Me</button>
请注意,在上述两种情况下,主题的下一个方法都可以在HTML组件模板中直接调用,因此主题具有公共访问修饰符(默认值)。这样就不需要在Typescript中使用onCLick方法。
<button (click)="subject.next(0)">Click Me</button>
按照哈南的建议
向按钮添加模板变量名,并使用@ViewChilds
获取元素引用。创建一个RxJS可观察使用fromEvents
,然后使用SwitchMap
高阶可观察的方法。
.
.
.
@ViewChild('refreshButton') refreshButton: ElementRef;
.
.
.
ngAfterViewInit(): void {
const click$ = fromEvent(this.refreshButton.nativeElement, 'click');
this.model$ = click$.pipe(
startWith(0),
switchMap(_ => {
return this.changeTransferActionsService
.getActionsWithNotesById(this.model.id)
.pipe(
map((x) => x.result),
);
}));
}
.
.
.
<button #refreshButton>Click Me</button>
.
.
.
总之,如果用户通过点击随意启动刷新,解决方案3最有意义,因为它不需要引入“虚拟”主题。
然而,subject方法有助于判断可观察对象是否应该从任何地方以编程方式发出……只需在subject上调用下一个方法,可观察对象就可以在命令上发出值。
您知道,这个主题还有很多内容,一种真正的反应式方法可能会启动您关于使用基于主题/行为主题/异步主题等的共享可注入单例服务和订阅的思考过程。不过,这些都是架构和设计决策。谢谢你的建议。
您可以获取刷新Btn引用并从其单击事件创建流,然后使用虚拟条目启动它。现在你有一个刷新流,然后像这样把它切换到你的数据流:
组成部分
@ViewChild('refreshButton') refreshBtn:ElementRef;
model$: Observable<any>;
ngAfterViewInit() {
let click$ = fromEvent(this.refreshBtn.nativeElement, 'click')
this.model$ = click$.pipe(startWith(0),
switchMap(_=> {
return this.changeTransferActionsService
.getActionsWithNotesById(this.model.id)
.pipe(
map((x) => x.result),
);
}));
}
样板
与使用2个异步管道不同,只使用1个异步管道和ngLet
,这将简化模板,您不必使用share()
:
<button #refreshButton >Refresh</button>
<ng-container *ngLet="(model$ | async) as model">
<div *ngIf="model.length > 0" class="card mb-3 shadow">
<div class="card-header">Actions Notes</div>
<div class="card-body">
<mat-list *ngFor="let action of model">
<div class="small">
<strong>
{{action.createdDate | date:'dd/MM/yyyy HH:mm'}}
{{action.createdBy}}
</strong>
</div>
<div>{{action.notes}}</div>
</mat-list>
</div>
</div>
<button (click)="onClick()">name</button>
</ng-container>
但要务实,不要花太多的精力让它完全被动。您以前的解决方案也很好,您只需要对模板进行改进。
注意:在这种情况下,您可以使用*ngIF
来代替*ngLet
我对angular是个新手,开始学习angular 4。数据未与使用异步管道的组件上的指令绑定。请帮忙 用户服务使用HTTP请求从API获取数据: user.service.ts 在这里,我使用用户列表的可观察用户[]界面: user.component.ts 订阅可观察用户变量的异步管道模板: user.component.html
关于Mono用法的小问题。反应管道中出现错误(new MyCustomException()) 我有一个非常简单的业务用例:使用Spring Webflow 步骤1:对第三方rest API进行HTTP调用 根据第一方rest API的响应,如果只有第一个响应符合条件,则使用map函数将响应转换为MyPojo。但如果不符合条件,则应引发自定义异常 因此,我写了以下内容: 请问正确的方法是什么? 如
我正在处理一个反应式quarkus后端服务,它执行以下操作。 使用与postgres交互的Hibernate反应式Panache从后端获取记录列表 使用记录的标识符,从另一个远程服务获取数据 我正在使用Mutiny来执行反应式管道。远程服务和数据库集成都以非阻塞方式单独工作。我只是需要帮助写一个连接这些的管道。例如:下面的例子 我被困在处理统一包装列表,然后试图处理列表中的单个项目。要么是Uni
问题内容: 在过去的几个小时中,我一直在努力解决这个问题,但无法解决。我想我仍然必须习惯于函数式编程风格;) 我写了一个递归函数,它遍历目录结构并对某些文件进行处理。此功能使用异步IO方法。现在,我要在完成整个遍历后执行一些操作。 如何确保在执行完所有调用但仍使用异步IO功能后执行此操作? 问题答案: 查找“ 步骤”模块。它可以链接异步函数调用,并将结果从一个传递到另一个。
问题内容: 我正在尝试使用新的react useReducer API来获取一些数据,并停留在需要异步获取的阶段。我只是不知道如何:/ 如何将数据获取放置在switch语句中,或者这不是应该完成的方式? 我试图这样做,但它不能与异步一起工作;( 问题答案: 这是一个有趣的案例,示例没有涉及。我认为减速器不是异步加载的正确位置。来自Redux的心态,您通常会将数据加载到其他位置,例如以thunk,可
本文向大家介绍bootstrap jquery dataTable 异步ajax刷新表格数据的实现方法,包括了bootstrap jquery dataTable 异步ajax刷新表格数据的实现方法的使用技巧和注意事项,需要的朋友参考一下 异步请求 数据处理函数packagingdatatabledata,异步请求返回的data.test_env_all必须是一个json格式数据