Arthur Le Calvez
Arthur Le Calvez

Reputation: 433

Mat-sort is not working even though my datasource _sort variable does change

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

Answers (1)

Francisco Baeza
Francisco Baeza

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.

Stackblitz example

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

Related Questions