angular - 如何从服务中封装的流中获取已检查的用户?
问题描述
有一个服务UsersService
包含用户逻辑:
interaface User {
id: number,
name: string,
checked?: boolean;
}
class UserService {
public users$ = new BehaviorSubject<User[]>([]);
public load() {
this.http.get('users').subscribe((users: Users[] => this.users$.next(users));
}
public get users() {
return this.users$.asObservable();
}
}
我从组件内部的服务中获取数据:
public users$: Observable<User[]>;
constructor(private userService: UserService) {
this.users$ = this.userService.users;
}
模板是:
<div> *ngFor="let user of users$ | async">
<div>{{ user.name }}</div>
<div><mat-checkbox [(ngModel)]="user.checked"></mat-checkbox></div>
</div>
<div>Checked users: {{ checkedusers | json }}</div>
如何{{ checkedusers | json }}
在更新一个复选框或所有复选框后使用流中的 rxjs 方法获取所有已检查用户并将其封装到服务中?
解决方案
像这样的东西似乎有效:
import { Injectable } from '@angular/core';
import { merge, of, Subject } from 'rxjs';
import { map, scan } from 'rxjs/operators';
export interface User {
id: number;
name: string;
checked?: boolean;
}
@Injectable({ providedIn: 'root' })
export class UserService {
readonly userChangeSubject = new Subject<User>();
userChanged$ = this.userChangeSubject.asObservable();
allUsers$ = of(userData);
updateUser(user: User, checked: boolean) {
const updatedUser = { ...user, checked: checked };
this.userChangeSubject.next(updatedUser);
}
checkedUsers$ = merge(
this.allUsers$,
this.userChanged$
).pipe(
scan((users: User[], user: User) => users.map((u) => u.id === user.id ? user : u)),
map(users => users.filter((u) => u.checked))
);
}
export const userData: User[] = [
{ id: 1, name: 'Captain Jack', checked: false },
{ id: 2, name: 'Mal Reynolds', checked: false },
{ id: 3, name: 'NaomiNagata', checked: false },
];
这是更新的链接:https ://stackblitz.com/edit/angular7-rxjs-ha6suw
- 当用户的检查更改时,主题会发出用户。
- 将
allUsers$
需要更改以调用您的 http 端点 - 当检查或未选中复选框时,从组件调用了更新器。它使用适当的检查标志创建一个新的用户对象并将其发送到主题中。
- 将
checkedUsers$
原始用户集与每个发出的更改用户合并。然后它scan
用于保留用户数组。当发出更新的用户时,它会在数组中找到该用户并替换它。然后它将结果数组映射为仅显示那些被选中的数组。
更新:根据 OP,添加了“全选”和“取消全选”功能。
@Injectable({ providedIn: 'root' })
export class UserService {
// User or null for all users
// Defined as a tuple with the user and checked flag
readonly userCheckedSubject = new Subject<[User | null, boolean]>();
userChecked$ = this.userCheckedSubject.asObservable();
// This would be an http.get to get the users
retrievedUsers$ = of(userData);
allUsers$ = merge(this.retrievedUsers$, this.userChecked$).pipe(
// Use array destructuring to access the tuple values
scan((users: User[], [changedUser, checked]: [User | null, boolean]) =>
this.processUsers(users, changedUser, checked)
),
shareReplay(1)
);
checkedUsers$ = this.allUsers$.pipe(
map((users) => users.filter((u) => u.checked)),
shareReplay(1)
);
updateUser(user: User | null, checked: boolean) {
this.userCheckedSubject.next([user, checked]);
}
processUsers(
users: User[],
changedUser: User | null,
checked: boolean
): User[] {
if (changedUser) {
// Update the one changed item
const updatedUser = { ...changedUser, checked: checked };
return users.map((user) =>
user.id === updatedUser.id ? updatedUser : user
);
} else {
// Update each item
return users.map((user) => ({ ...user, checked: checked }));
}
}
}
推荐阅读
- node.js - 在 CLI 应用程序中实现 Github 身份验证和授权
- prolog - SWI Prolog 中的约束处理规则:“约束存储”是否仅在顶级目标处理期间存在?
- oracle - PL/SQL 语句被忽略,SQL 语句被忽略
- django - Django 创建超级用户和管理模块
- python - 如何计算一个大数的 2 的幂模另一个大数?
- jquery - 有没有办法完全覆盖div中的复杂区域?
- nginx - asp net core 3 在发布后获取带有正文内容的 POST 操作的 BadRequest 响应
- c# - 在以下代码中遇到合并冲突
- javascript - 动态改变一个js文件的src
- indexing - 公式 - 单元格值匹配结果为 Concat 公式