Reputation: 433
In an Angular app I am loading data from a database using
data.service.ts
import {Injectable} from '@angular/core';
import {Post} from '../Post';
import {Observable, of} from 'rxjs';
import { HttpClient } from '@angular/common/http';
@Injectable()
export class DataService {
constructor(private http: HttpClient) {
}
getData(): Observable<Post[]> {
return this.http.get<Post[]>('http://localhost:80/Findall');
}
getCategories() {
return this.categories;
}
findCaldera(index: string) {
console.log('find: ' + index);
return this.http.get('http://localhost:80/Find/' + index);
}
updateCaldera(index: string, data) {
console.log('find: ' + index);
return this.http.put('http://localhost:80/Update/' + index, data);
}
addPost(data) {
console.log('add: ' + JSON.stringify(data));
return this.http.post<Post>('http://localhost:80/Add', data);
}
deletePost(index: string) {
console.log('delete: ' + index);
return this.http.delete('http://localhost:80/Delete/' + index, {responseType:'text'});
}
}
This therefore returns an observable to my dashboard where the data is displayed
dashboard.component.ts
import {Component, ViewChild} from '@angular/core';
import {DataService} from '../data/data.service';
import {Post} from '../Post';
import {DataSource} from '@angular/cdk/table';
import {Observable} from 'rxjs/Observable';
import {AuthService} from '../auth.service';
import {PostDialogComponent} from '../post-dialog/post-dialog.component';
import {EditComponent} from '../edit/edit.component';
import {MatDialog, MatSort, MatTableDataSource} from '@angular/material';
@Component({
selector: 'app-dashboard',
templateUrl: './dashboard.component.html',
styleUrls: ['./dashboard.component.css']
})
export class DashboardComponent {
constructor(private dataService: DataService, public auth: AuthService, public dialog: MatDialog) {
}
@ViewChild(MatSort) sort: MatSort;
displayedColumns = ['Borrower1','_id', 'edit','delete'];
dataSource: PostDataSource |null;
ngOnInit(){
this.dataSource = new PostDataSource(this.dataService, this.sort);
}
ngAfterViewInit(){
this.sort.sortChange.subscribe(()=>{console.log(this.dataSource)});
}
deletePost(id) {
if (this.auth.isAuthenticated()) {
this.dataService.deletePost(id).subscribe(()=>{
this.dataSource = new PostDataSource(this.dataService, this.sort);
});
} else {
alert('Login in Before');
}
}
editDialog(id): void {
let dialogRef = this.dialog.open(EditComponent, {
width: '100%',
data: id,
});
dialogRef.componentInstance.event.subscribe((result) => {
console.log(result.data)
this.dataSource = new PostDataSource(this.dataService, this.sort);
});
}
openDialog(): void {
let dialogRef = this.dialog.open(PostDialogComponent, {
width: '100%',
data: 'Add Post'
});
dialogRef.componentInstance.event.subscribe((result) => {
console.log(result.data)
this.dataService.addPost(result.data).subscribe(()=>{
this.dataSource = new PostDataSource(this.dataService, this.sort);
});
});
}
}
export class PostDataSource extends DataSource<any> {
constructor(private dataService: DataService, private _sort: MatSort) {
super();
}
connect(): Observable<Post[]> {
console.log("hi1")
return this.dataService.getData();
}
disconnect() {
}
}
When i click on the sort arrow on the html page an event is emitted as i can see from this.sort.sortChange.subscribe(()=>{console.log(this.dataSource)});
within the dataSource the _sort
property changes to reflect the changes i make by click on the sort arrow in the view i.e after 1 click the dataSource._sort.order = "asc"
and then after another click dataSource._sort.order = "desc"
. However the data in the table does not change. There are many example that use MatTableDataSource but I have read that it isn't good practice to use this when using http to get my data.
Thanks
Upvotes: 2
Views: 2486
Reputation: 81
When you use MatSort with asynchronous data you should listen the sort changes and for every one make a call to get the sorted data.
Here is an example. I hope this help.
UPDATED ANSWER
If you use DataSource then your data wont be sorted automatically, you have to listen sort changes. One way of doing it could be the following
import { startWith } from 'rxjs/operators';
import { combineLatest } from 'rxjs';
export class PostDataSource extends DataSource<any> {
constructor(private dataService: DataService, private _sort: MatSort) {
super();
}
connect(): Observable<Post[]> {
return combineLatest(
this.dataService.getData(),
this.sort.sortChange.pipe(startWith(null)),
(data, sort) => {
return this.sortData(data, sort);
}
)
}
disconnect() {
}
sordData(data, sort) {
// Sort data
return this.data;
}
}
Notice sortChange has startWith. That is because combineLatest require all observable to emit at least once
Upvotes: 1