Potrzebuję żądać danych z mojego interfejsu API usług REST przy użyciu parametru Angular 4.3 HttpClient. Mój komponent używa klasy Subject
, aby zapewnić filtrowanie po stronie serwera (gdy użytkownik wpisuje to hasło) i stronicowanie, ale muszę też pozwolić na wielokrotny wybór elementów za pomocą pól wyboru w siatce danych wyników.Jak zezwolić na zaznaczanie wielu elementów (pól wyboru) podczas korzystania z filtrowania po stronie serwera i stronicowania przez obiekt RXJS Temat:
Mam następujący kod do tworzenia siatki danych:
<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$
jest observable<Vehicle[]>
a dane są wyświetlane poprawnie, jednak przy zmianie sprawdzany stan dla niektórych pól, właściwość w vehicle.checked
dane obserwowalne są niezmienne.
Czego mi brakuje?
Oto pełna źródło komponent:
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);
}
}
serwis 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);
}
}
co masz na myśli, że się nie zmienia? oczywiście jest, w zakresie ngFor, nigdzie indziej. Podobnie jak zamierzone zachowanie. Musisz uchwycić zdarzenie w kodzie i przesunąć je z powrotem przez źródło. – bryan60
Ale jak to zrobić? W przypadku innych zmiennych, jeśli użyję '[(ngModel)] =" varName ", zostanie on zaktualizowany w mojej klasie. Jak zrobić to samo dla tego obserwowalnego? –
, więc skąd wziąłeś 'pojazdy $'? czy jesteś w stanie przetworzyć go w kodzie onChange? coś takiego: '(change) =" vehicle.checked =! vehicle.checked; vehicles $ = Observable.of (xxxxx) "' –