Angular 9:如何处理包含Observable安全组数组的服务器数据并筛选差异项展示
解决思路和代码修正
首先,我得指出你当前代码里的几个关键问题,然后一步步帮你修正:
1. 核心问题分析
- HTML结构错误:
<select>的直接子元素只能是<option>或<optgroup>,你用<span>包裹<option>的写法不符合规范,浏览器会直接忽略这个<span>,导致循环逻辑失效。 - Observable重复订阅:每个服务器的
securityGroups是Observable,模板里多次使用async管道会触发多次HTTP请求,不仅浪费资源,还会导致数据状态混乱。 - 过滤逻辑不清晰:三层
*ngFor的写法会生成大量重复的选项,而且没有明确的筛选逻辑,无法实现你想要的“只展示符合条件的服务器”的效果。
2. 组件代码修正:预处理服务器的安全组数据
我们先把所有服务器的安全组数据提前获取并转换成同步数组,避免模板里的重复订阅:
ngOnInit(): void { forkJoin( this.serverService.getServer(), this.securityGroupService.getSecurityGroups() ) .pipe(takeWhile(() => this.alive)) .subscribe(([servers, groups]) => { // 先收集所有服务器的安全组请求Observable const serverSecurityGroupRequests = servers.map(server => this.serverService.getServerById(server.id) .pipe(map(serverData => serverData["security_groups"])) ); // 并行获取所有服务器的安全组数据 forkJoin(serverSecurityGroupRequests) .pipe(takeWhile(() => this.alive)) .subscribe(securityGroupsList => { // 将安全组数据合并到服务器对象中,现在securityGroups是实际数组而非Observable this.servers = servers.map((server, index) => ({ ...server, securityGroups: securityGroupsList[index] })); }); // 处理全局安全组数据 this.securityGroupArray = groups['security_groups'].map(item => ({ ...item, expanded: false, })); }); }
3. 明确过滤逻辑并实现
根据你的需求“仅展示securityGroupArray中与这些名称不同的项对应的服务器名称”,我理解为:展示那些服务器,它们的安全组中存在至少一个不在全局安全组(securityGroupArray)里的安全组。如果你的需求是“展示那些服务器的所有安全组都不在全局安全组里”,只需要把下面的some改成every即可。
首先在组件里添加一个过滤方法:
// 判断服务器是否有不在全局安全组中的安全组 hasNonGlobalSecurityGroups(server: any): boolean { // 先提取全局安全组的所有名称 const globalGroupNames = this.securityGroupArray.map(group => group.name); // 检查服务器的安全组中是否有不在全局列表里的项 return server.securityGroups.some(serverGroup => !globalGroupNames.includes(serverGroup.name)); }
然后修改HTML代码,去掉错误的<span>,并使用过滤方法筛选服务器:
<div class="form-group" [formGroup]="form"> <div class="col-sm-12"> <select class="form-control border-primary" formControlName="server"> <option [value]="''">select</option> <!-- 只渲染符合条件的服务器选项 --> <option *ngFor="let server of servers" [value]="server.id" *ngIf="hasNonGlobalSecurityGroups(server)" > {{ server.name }} </option> </select> </div> </div>
4. 如果需求是“展示未使用指定安全组的服务器”
如果你其实是想实现“选择一个安全组后,下拉框展示没有使用该安全组的服务器”,可以再添加一个安全组的下拉选择框,然后动态过滤服务器:
组件新增代码:
// 新增一个FormControl用于选择安全组 selectedSecurityGroup = new FormControl(''); // 过滤未使用指定安全组的服务器 get filteredServers() { if (!this.selectedSecurityGroup.value) return this.servers; const targetGroupName = this.securityGroupArray.find(g => g.id === this.selectedSecurityGroup.value)?.name; if (!targetGroupName) return this.servers; return this.servers.filter(server => !server.securityGroups.some(group => group.name === targetGroupName) ); }
对应HTML:
<!-- 新增安全组选择框 --> <div class="form-group"> <select class="form-control border-primary" [formControl]="selectedSecurityGroup"> <option [value]="''">选择要排除的安全组</option> <option *ngFor="let group of securityGroupArray" [value]="group.id"> {{ group.name }} </option> </select> </div> <!-- 服务器选择框,使用过滤后的数组 --> <div class="form-group" [formGroup]="form"> <div class="col-sm-12"> <select class="form-control border-primary" formControlName="server"> <option [value]="''">select</option> <option *ngFor="let server of filteredServers" [value]="server.id"> {{ server.name }} </option> </select> </div> </div>
这样就能实现动态过滤的效果啦~
内容的提问来源于stack exchange,提问作者Dave
相关产品推荐
相关产品推荐

