angular - 通过 RXJS 主题使用服务器端过滤和分页时如何允许多个项目选择(复选框)

标签 angular

我需要使用 Angular 4.3 HttpClient 从我的 REST api 请求数据。我的组件使用 Subject类来提供服务器端过滤(当用户键入术语时)和分页,但我还需要使用结果数据网格中的复选框允许多项选择。

我有以下代码来创建数据网格:

<tr *ngFor="let vehicle of vehicles$ | async">
    <td><input type="checkbox" name="vehicle-selection" id="vehicle-{{vehicle.id}}" value="{{vehicle.id}}" [ngModel]="vehicle.checked" (ngModelChange)="setChecked(vehicle.id, $event)" /></td>
    <td>{{vehicle.chassis}}</td>
    <td>{{vehicle.lastUpdate || '' | amFromUtc | amDateFormat: 'DD/MM/YYYY'}}</td>
    <td>{{vehicle.description}}</td>
    <td>{{vehicle.location}}</td>
</tr>

vehicles$是一个 observable<Vehicle[]>并且数据显示正确,但是,当我更改某些复选框的选中状态时,vehicle.checked数据绑定(bind)可观察对象中的属性未更改。

我错过了什么?

这是完整的组件源:

import { Component, OnInit, AfterViewInit } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';
import { Router } from '@angular/router';

import { NotificationsService } from 'angular2-notifications';
import { ConfirmationService } from '@jaspero/ng2-confirmations';

import 'rxjs/add/observable/of';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/debounceTime';
import 'rxjs/add/operator/distinctUntilChanged';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/merge';
import 'rxjs/add/operator/pluck';
import 'rxjs/add/operator/startWith';
import 'rxjs/add/operator/switchMap';


import { ResolveEmit, ConfirmSettings } from '../../shared/interfaces/jaspero';
import { VehiclesService } from '../../core/services/vehicles.service';
import { Vehicle } from '../../shared/interfaces/vehicle';
import { PagedResults } from 'app/shared/interfaces/paged-results';
import { distinctUntilChanged } from 'rxjs/operator/distinctUntilChanged';

@Component({
  selector: 'app-vehicles-search',
  templateUrl: './vehicles-search.component.html',
  styleUrls: ['./vehicles-search.component.scss'],
  providers: [VehiclesService]
})
export class VehiclesSearchComponent implements OnInit {
  vehicles$: Observable<Vehicle[]>;
  totalRecords$: Observable<number>;
  page = 1;
  searchTerm = '';

  searchTermStream = new Subject<string>();
  pageStream = new Subject<number>();

  constructor(
    private vehiclesService: VehiclesService,
    private router: Router,
    private notification: NotificationsService,
    private confirmation: ConfirmationService
  ) { }

  search(term: string) {
    this.searchTermStream.next(term);
  }

  assignAnomaly() {
    this.vehicles$
      .map(m => {
        console.log(m); return m.filter(f => f.checked);
      })
      .subscribe(res => {
        if (res.length < 1) {
          this.notification.warn('Associar Anomalia', 'Você deve selecionar um veículo antes.');
        }
      });
  }

  setPage(page: number) {
    this.pageStream.next(page);
  }

  ngOnInit(): void {
    const searchSource = this.searchTermStream
      .debounceTime(300)
      .distinctUntilChanged()
      .map(term => {
        this.searchTerm = term;
        return { search: term, page: 1 };
      });

    const pageSource = this.pageStream
      .map(pageNumber => {
        this.page = pageNumber;
        return { search: this.searchTerm, page: pageNumber };
      });

    const source = pageSource
      .merge(searchSource)
      .startWith({ search: this.searchTerm, page: this.page })
      .switchMap((params: { search: string, page: number }) => {
        return this.vehiclesService.getVehicles(params.search, params.page);
      });

      this.totalRecords$ = source.pluck('totalRecords');
      this.vehicles$ = source.pluck('results');
  }

  setChecked(val, ev) {
    console.log(val);
    console.log(ev);
  }
}

HTTP 服务

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { HttpClient } from '@angular/common/http';
import { environment } from '../../../environments/environment';

import { PagedResults } from '../../shared/interfaces/paged-results';
import { Vehicle } from '../../shared/interfaces/vehicle';

import 'rxjs/add/operator/toPromise';
import { forEach } from '@angular/router/src/utils/collection';

@Injectable()
export class VehiclesService {

  private baseUrl = `${environment.apiUrl}/api/vehicles`;  // URL to web api

  constructor(private http: HttpClient) { }

  getVehicles(filter: string, page: number): Observable<PagedResults<Vehicle[]>> {
    filter = filter ? `/${filter}` : '';
    return this.http
      .get<Vehicle[]>(`${this.baseUrl}/page/${page}${filter}`, {observe: 'response'})
      .map((res) => {
        const totalRecords = +res.headers.get('X-InlineCount');
        const results = res.body;

        for (let i = 0; i < results.length; i++) {
          results[i].checked = false;
        }

        return {
          results: res.body,
          totalRecords: totalRecords
        };
      })
      .catch(this.handleError);
  }

  getVehicleById(id: number): Observable<Vehicle> {
    return this.http.get(`${this.baseUrl}/${id}`)
      .map((res: Response) => res.json())
      .catch(this.handleError);
  }

  private handleError(error: any): Promise<any> {
    console.error('An error occurred', error);
    return Promise.reject(error.message || error);
  }
}

最佳答案

您可以尝试使用 VehicleArray 而不是 Observable,您将其设为空,然后订阅 getVehicles ,并将它们添加到数组中或替换它们。

关于angular - 通过 RXJS 主题使用服务器端过滤和分页时如何允许多个项目选择(复选框),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47318815/

相关文章:

javascript - 从 Javascript/typescript 对象的非空属性创建一个数组

ios - 如何通过使用 Ionic2 在 iPhone/iPad 上点击返回键转到下一个输入?

angular - Angular 中的 Async/await 或 Observable

javascript - Ionic 2导入查找js而不是ts文件

angular - 数据路径 ""不应具有其他属性(allowedCommonJsDependencies)

angular - 按照惰性模块结构使用 NgRx 存储创建嵌套切片

angular - 原始的意思是什么?

javascript - Angular 动画作为单独的文件而不是内联的

javascript - 如何使用 Visual Studio Code 调试 Angular 4 单元测试

angular - 获取点击的div的宽度、高度和偏移量——Angular 2