2017-11-15 19 views
7

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); 
    } 
} 
+0

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

+0

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? –

+0

, 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) "' –

Odpowiedz

-1

myślę, że należy użyć [(ngModel)]="vehicle.checked" w polu wyboru wiążącego.

[ngModel]="vehicle.checked" to tylko jednokierunkowe wiązanie, to po prostu zmieni ui po zmianie właściwości pojazdu.

Jeśli chcesz, aby to pole wyboru wpłynęło na sprawdzoną właściwość, powinieneś użyć wiązania dwukierunkowego, czyli [(ngModel)]="vehicle.checked".

+0

Próbowałem już tego, ale jak wskazał inny użytkownik, zmiana pozostaje w zakresie ngFor, dlatego moja zmienna modelu nie jest aktualizowana. –

0

Można spróbować użyć Array z Vehicle zamiast Observable, zaczynasz to pusty, a następnie zapisać się do getVehicles i dodać je do tablicy lub ich zastąpienia.