I am putting together an Angular Material Table to display results returned from the server. The data structure is as follows:
export class Question
{
question : string;
anonymous : boolean;
}
export class SearchResult
{
totalCount : number;
pageBeginIndex : number;
pageSize : number;
questions : Question[];
}
The http get is wrapped in a function that evaluates to an observable:
public getSearchQuestions = (queryString : string, startIndex : number, count : number): Observable<SearchResult> =>
{
let url = this.baseUrl + "search?queryString=" + queryString + "&startIndex=" + startIndex + "&count=" + count;
return this.http.get(url, { headers : this.getHeaders() })
.map(response => response.json() as SearchResult)
.catch(error => this.handleError(error));
}
The bit that I'm having challenges with is the connect() function in the Table's DataSource definition. The typical examples for this show the return of a function which fetch the results directly from the server evaluating to an Observable[]. My case is more complex because I need to extract the Observable return by http get function is wrapper to the Observable required by the DataSource::connect() contract. I do not want to do this unwrapping within the http get data map because I need to also extract the totalCount field within the DataSource at the same time. This is where I have got to:
export class SearchDataSource extends DataSource<any>
{
recordCount : number;
constructor(private service: IntelienceService, private searchQuery : string, private _paginator: MatPaginator) {
super();
}
connect(): Observable<Question[]> {
const startIndex = this._paginator.pageIndex * this._paginator.pageSize;
return Observable.create((observer) : Observable<Question[]> => {
return this.service.getSearchQuestions(this.searchQuery, startIndex, this._paginator.pageSize).map(
searchResult => {
// Execution never reaches here
this.recordCount = searchResult.totalCount;
return searchResult.questions },
error => { console.log('error') }
);
});
}
disconnect() { }
}
While this compiles the Table's Paginator is throwing an internal error suggesting that the value returned from connect is undefined - and indeed execution is never reaching the point indicated by the comment in the above code. Any help to understand how I can create a new Observable that wraps an existing one and maps the data in the way I have indicated would be much appreciated.
=== EDIT ===
I got a little bit further with this revision:
connect(): Observable<SearchQuestion[]> {
const startIndex = this._paginator.pageIndex * this._paginator.pageSize;
return Observable.create(observer => {
this.service.getSearchQuestions(this.searchQuery, startIndex, this._paginator.pageSize).subscribe(
(searchResults) => {
observer.next(() => { return searchResults.questions; });
observer.complete();
},
error => { console.log('error') }
);
});
}
This now invokes the http get in getSearchQuestions, however the observer.next() function is not being called and the paginator continues to throw undefined errors:
ERROR TypeError: Cannot read property 'pageIndex' of undefined
at SearchDataSource.webpackJsonp.../../../../../src/app/search/search.component.ts.SearchDataSource.connect (search.component.ts:61)
You do not need Observable.create() at all.
startIndex shouldn't be a constant, and it should be calculated each time you turn the page.
export class SearchDataSource extends DataSource<Question> {
recordCount: number;
constructor(private intelienceService: IntelienceService,
private searchQuery: string,
private _paginator: MatPaginator) {
super();
}
connect(): Observable<Question[]> {
return this.intelienceService.getSearchQuestions(this.searchQuery, this.getStartIndex(), this._paginator.pageSize)
.map(searchResult => {
this.recordCount = searchResult.totalCount;
return searchResult.questions;
}, () => { console.log('error'); }
);
}
disconnect() {
// intentionally left blank
}
private getStartIndex(): number {
return this._paginator.pageIndex * this._paginator.pageSize;
}
}
Bonus:
Instead of interpolating url, you should use http options:
this.http.get(url, {
headers: this.getHeaders(),
params: {
queryString: queryString,
startIndex: startIndex,
count: count
}
});
Also there is a small typo in the service name:
IntelienceService => IntelligenceService
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With