1

I'm integrating angular material and Google api. I want to show in a table the response of the api. The problem is that the mat-cell of the rows of the mat-table are not populated, but the row is showned. This is my table:

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

    <ng-container matColumnDef="name">
      <mat-header-cell *matHeaderCellDef> Name </mat-header-cell>
      <mat-cell *matCellDef="let user"> {{user.name}} </mat-cell>
    </ng-container>
    <ng-container matColumnDef="age">
      <mat-header-cell *matHeaderCellDef> Age </mat-header-cell>
      <mat-cell *matCellDef="let user"> {{user.age}} </mat-cell>
    </ng-container>
    <ng-container matColumnDef="city">
      <mat-header-cell *matHeaderCellDef> City </mat-header-cell>
      <mat-cell *matCellDef="let user"> {{user.city}} </mat-cell>
    </ng-container>
    <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
    <mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
  </mat-table>

This is an interface that I have created:

    export interface User { name: string; age: number; city: string; }

This is the component associated with the table:

    export class UsertableComponent implements OnInit, OnChanges {
  @Input() apiReady: boolean;

  dataSource: UserDataSource;
  displayedColumns = ['name', 'age', 'city'];

  constructor(private userService: UserService) {

  }

  ngOnInit() {

  }

  ngOnChanges(changes: SimpleChanges) {
    if (this.apiReady) {
      this.dataSource = new UserDataSource(this.userService);
    }
  }
}

export class UserDataSource extends DataSource<any> {
  constructor(private userService: UserService) {
    super();
  }

  connect(): Observable<User[]> {
    return this.userService.getUsers();
  }

  disconnect() {

  }
}

And here, finally, the nightmare. The service that calls the gapi and return the data. I can ensure that the api respond and in particular this line of code response.result.users[0].name.fullName correspond to a string object with a value.

export class UserService {
  private serviceUrl = environment.apiUrl + '/getcust/';
  private apiLoaded = false;
  constructor(private http: HttpClient) { }

  getUsers(): Observable<User[]> {
    /* // THIS WORKS!!!
        const u: User = {
          'name': 'ss',
          'city': 'città',
          'age': 3
        };
        return Observable.create(observable => {
          observable.next([u]);
          observable.complete();
        });
     */

    return Observable.create(observable => { // THIS DOESN'T WORK
      return gapi.client.directory.users.list({
        'customer': 'my_customer',
        'maxResults': 1,
        'orderBy': 'email'
      }).then(response => {

        const u: User = {
          'name': response.result.users[0].name.fullName,
          'city': 'citta',
          'age': 3
        };

        observable.next([u]);
        observable.complete();
      });
    });
  }
}

As you see in the comment, the commented lines works, the others does not.

Result with empty cells

Result with populated cells, without calling GAPI

Edric
  • 24,639
  • 13
  • 81
  • 91
  • What does `gapi.client.directory.users.list` return? A promise? – David Mar 18 '18 at 18:25
  • I guess so. Thats the quickstart guide for javascript: https://developers.google.com/admin-sdk/directory/v1/quickstart/js and this is a question that shows how to do it with typescript: https://stackoverflow.com/questions/38091215/import-gapi-auth2-in-angular-2-typescript – Lorem Ipsum Mar 18 '18 at 19:10
  • And you don't get any error in the console? Maybe try without the `return` before the API call. – David Mar 18 '18 at 19:12
  • The point is that when the observable complete, the row appears in the table, but the cells are not populated. But the object that i'm putting in the next() method is correct. I have tried also with exactly the same object of the example that works, and still the cells are empty: const u: User = { 'name': 'ss', 'city': 'città', 'age': 3 }; – Lorem Ipsum Mar 18 '18 at 19:16
  • already tried, nothing. – Lorem Ipsum Mar 18 '18 at 19:16

1 Answers1

2

The solution is:

Import this:

import {ChangeDetectorRef} from '@angular/core';

The constructor of the component:

constructor(private cd: ChangeDetectorRef) {
  }

In the ngInit initialize the datasource:

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

Use BehaviorSubject (and the method asObservable) to change the content of the datasource at any time, but when the data changes in the table don't forget to call:

this.cd.detectChanges();

to update cells content