2

I have an api which send data from backend, so when I try to get this data in my angular the data is not loaded in the first time, and my table stay empty, but if for example print the data that come from banckend before setting it in my DataSource, my table is fill correctly.

My code is:

user-datasource.ts

export class UserListDataSource extends DataSource<User> {
  data: User[];
  paginator: MatPaginator;
  sort: MatSort;

  constructor(private usersService: UsersService) {
    super();
  }

  connect(): Observable<User[]> {
    this.data = this.usersService.usersList();
    //this.data.forEach(u => console.log(u.id)); <<---------- When I log this, My data is fill corectly
    const dataMutations = [
      observableOf(this.data),
      this.paginator.page,
      this.sort.sortChange
    ];

    return merge(...dataMutations).pipe(map(() => {
      return this.getPagedData(this.getSortedData([...this.data]));
    }));
  }
  ...

}

userService

export class UsersService {

  users: User[];

  constructor(private http: HttpClient) {}

  usersList() {    
    this.http.get(`${environment.apiUrl}/users`).pipe(
      map((jsonArray: Object[]) =>  jsonArray.map(jsonItem => User.fromJson(jsonItem)))
    ).subscribe((users: User[]) => { this.users = users; });

    return this.users;
  }

}

component

export class UserListComponent implements AfterViewInit, OnInit {
  @ViewChild(MatPaginator) paginator: MatPaginator;
  @ViewChild(MatSort) sort: MatSort;
  @ViewChild(MatTable) table: MatTable<User>;

  dataSource: UserListDataSource = new UserListDataSource(this.usersService);

  displayedColumns = ['id', 'email', 'username'];

  constructor(private usersService: UsersService) { }

  ngOnInit() {}

  ngAfterViewInit() {
    this.dataSource.sort = this.sort;
    this.dataSource.paginator = this.paginator;
    this.table.dataSource = this.dataSource;
  }
}

I'm not sure if I use the correct way to fill my table, or I miss something.

From what I see, I think the backend took a long time than the frontend to load data, in another word, frontend is not waiting the necessary time to get data from backend.

Is there any way to fix this please?


Note: I use angular material schematics to create all this, in the default code, it use a static data, which is not the solution for me, which I need to use dynamic data.

2 Answers 2

2

You should await for the server response before you send the users collections back.

UsersService

usersList(): Observable<User[]> {    
    return this.http.get(`${environment.apiUrl}/users`).pipe(
      map((jsonArray: Object[]) =>  jsonArray.map(jsonItem => User.fromJson(jsonItem)))
    );
}

UserService just returns the promise of the user's collection.
In your UserListComponent, create a MatTableDataSource of type User and await the data from the your service. Then, once it is fulfilled, add that data to the datasource.

export class UserListComponent implements OnInit, AfterViewInit {

  private users: User[] = [];
  dataSource = new MatTableDataSource<User>();
  columns: string[] = ['...'];

  @ViewChild(MatPaginator) paginator: MatPaginator;
  @ViewChild(MatSort) sort: MatSort;

  constructor(private service: UsersService) {}

  ngOnInit(): void {
    this.service.usersList().subscribe(users => {
      this.users = users;
      this.dataSource.data = this.users;
    });
  }

  ngAfterViewInit(): void {
    this.dataSource.sort = this.sort;
    this.dataSource.paginator = this.paginator;
  }
}

And, the last point. Use the dataSource input from the table tag to bind your MatTableDataSource to the table.

<table [dataSource]="dataSource">
  <!-- ... -->
</table>
Sign up to request clarification or add additional context in comments.

4 Comments

Thank you for your answer, this work very well with me, so from your solution I don't need to UserListDataSource?
Well, if you are not implement anything really tricky, there is no need to extend from DataSource. MatTableDataSource<TData> does this for you, indeed.
I'm sorry to ask, but is there any trick to stick with DataSource?
I don't understand the question, sorry, hehe. Could you explain it?
0

I'm not quite sure what exactly the problem is but I recently wrote a couple tables with angular material. Here is the simple way that I used to connect with a table.

export class UserDataSource extends DataSource<any> {

constructor (
    private userSettingsService: UserSettingsService) 
{
    super();
}

  public usersDataStream = new BehaviorSubject<IUser[]>([]);

  connect(): Observable<IUser[]> {
    return this.usersDataStream.asObservable();
  }
  disconnect() {
    this.usersDataStream.complete();
  }
}

And then in the component class:

public dataSource: UserDataSource;

ngOnInit(): void {
this.dataSource = new UserDataSource(this._userSettingsService);
}

and then the HTML template:

<mat-table [dataSource]="dataSource">
...
</mat-table>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.