Videgain
Videgain

Reputation: 195

Calling a method from an Angular view only once

I have built a table from angular materials. I have an object called "matricula" and in the first column I print the property matricula.matricula from a list of matriculas. In the second column I want to print some data I get calling a method from that matricula.matricula. I have my method defined in my Typescrypt document but as it works with a webservice, I only want to call the method for the objects that are shown at each moment (which variates as I have a paginator). I have tried calling the method from the view using {{method}}, but as Angular views work on real time, the method is being called all the time and the project crashes.

How could I do the call only once for each object matricula? I am sure it must be possible but I have no idea which tool or method I should use.

Here is the code from the view:


            <ng-container matColumnDef="matricula" style="flex: 0 0 10%;" >
                <th mat-header-cell *matHeaderCellDef> Matrícula </th>
                <td mat-cell *matCellDef="let matricula"height=70px> {{matricula.matricula}} </td>
            </ng-container>

            <ng-container matColumnDef="posicion" style="flex: 0 0 50%;">
                <th mat-header-cell *matHeaderCellDef> Ubicación </th>
                <td mat-cell *matCellDef="let matricula" height=70px> {{method(matricula.matricula)}} </td>
            </ng-container>

       

            <tr mat-header-row *matHeaderRowDef="mostrarColumnas"></tr>
            <tr mat-row *matRowDef="let matricula; columns: mostrarColumnas;"></tr>
        </table> 

Edit: Here is the code from the method:

    let matricula : MatriculaBuscada = {
      action : "ultima_posicion",
      matricula : placa
    }
    this.posicionService.posicion(matricula).subscribe(datos => {
    return datos;});
    console.log('método getDatos')
  }

The posicionService only calls a webservice which sends back a Json that is already mapped.

Upvotes: 1

Views: 1540

Answers (1)

Eliseo
Eliseo

Reputation: 57939

If you can not "paginate" your API (see this SO), I imagine that the best bet is subscribe to the matPaginator.changes.

I imagine you has a service with two functions: getAllData -that return the data incomplete- and getData(id) -that return the auxiliar data of one item

You can has in ngAfterViewInit some like: -I used in the e.g. the tipical material table with the periodic elements

  ngAfterViewInit() {
    //I use the setTimeout for avoid
    // the error "ExpressionChangedAfterItHasBeenCheckedError"
    setTimeout(()=>{
      //simple get the data, getAllData simply return an array os "positions"
      this.dataService.getAllData().pipe(
        map((res: any[]) => {
          //create an object with all the properties necesary
          return res.map((x) => ({
            position: x,  //<--this is the only I get
            name: null,   //the rest properties I put as null
            weight: 0,
            symbol: null,
            yet: false,  //<--add this new property
          }));
        })
      ).subscribe((res:any[])=>{
        this.dataSource=new MatTableDataSource(res)
        this.dataSource.paginator = this.paginator;
        this.initPaginator()  //<--this is the "key"
      });
  
    })
  }
  initPaginator(){
    //I subscribe to paginator.page
    //happens always you change the page or the page size
    this.paginator.page.pipe(
      startWith(1),
      ).subscribe((_) => {

      //get the data that really is showed
      //and filter only I not loaded before
      const data = this.dataSource.filteredData
        .slice(
          this.paginator.pageIndex * this.paginator.pageSize,
          (this.paginator.pageIndex + 1) * this.paginator.pageSize
        )
        .filter((x: any) => !x.yet);

      //if there're data
      if (data.length) {
        this.isLoadingResults=true;
        //create a forkJoin -and array of Observables-
        //e.g. at first is a forkJoin of the array:
        //[this.dataService.getData(1),
        //   this.dataService.getData(2),
        //   ...]
        forkJoin(
          data.map((x: any) => this.dataService.getData(x.position))
        ).subscribe((res: any[]) => {

          //in subscribe, try to find the data
          res.forEach((x) => {
            let item = this.dataSource.data.find(
              (d: any) => (d.position == x.position)
            );
            //and put the properties I received
            if (item) {
              item.name=x.name;
              item.weight=x.weight;
              item.symbol=x.symbol;
              item.yet=true;
            }
          });

          this.isLoadingResults=false
        });
      }
    });
  }

You can see the stackblitz

Upvotes: 1

Related Questions