web-dev-qa-db-fra.com

Comment maintenir le défilement vertical lors de la mise à jour Angular 5 tableau de données?

Je souhaite mettre fréquemment à jour ma table de données (Covalent td-data-table avec plusieurs ng-template) avec de nouvelles données extraites d'une API JSON REST. Plus de lignes que le navigateur ne peut en contenir, l'utilisateur peut donc avoir besoin de faire défiler verticalement. Mais lorsque je mets à jour les données de la table, elles sont complètement redessinées, c’est-à-dire que la position de défilement vertical est réinitialisée vers le haut, les info-bulles clignotent, etc. 

Hacks à par exemple enregistrer/restaurer le défilement vertical comme ci-dessous type de travail, mais ils créent beaucoup de désordre visuel, en particulier dans Firefox.

// save vertical scroll
this.scrollTop = this.tableElt.nativeElement.querySelector('.td-data-table-scrollable').scrollTop;

// update table data here
this.data = newData;

// restore vertical scroll
setImmediate(() => {
    this.tableElt.nativeElement.querySelector('.td-data-table-scrollable').scrollTop = this.scrollTop;
  }
});

Comment puis-je mettre à jour proprement les données d'une table (ou de tout autre composant réellement) sans piratage informatique pour réinitialiser les positions de défilement et supporter beaucoup de comportements de clignotement? 

S'il n'y a pas de solution utilisant la table de données Covalent, existe-t-il un autre contrôle Angular 2+ qui gère cela correctement?

Capture d'écran animée du problème: le défilement vertical est rétabli lorsque les données sont mises à jour. Le défilement vertical doit être maintenu dans les mises à jour des données .  screencapture

6
bunt

Je vous suggère de passer à un matériau angulaire et de le lier à une source de données observable.

https://material.angular.io/components/table/overview#observable-stream-of-data-arrays

Lorsque la source de données (Observable) est mise à jour avec de nouvelles données, le DOM est mis à jour et il n'est pas nécessaire de suivre les événements de défilement.

Si vous êtes inquiet à propos du nombre d'articles énumérés sur une page, la pagination est prise en charge de manière simple. . https://material.angular.io/components/table/overview#pagination

SideNote: Basculez sur un matériau angulaire car leurs composants sont bien documentés, avec des exemples et des exemples de codes.

2
steve biko

Vous pouvez essayer d’utiliser une fonction trackBy. Cette fonction sera utilisée pour déterminer quelles lignes de votre *ngFor ont été modifiées pour optimiser les retraits.

<tbody>
<tr td-data-table-row *ngFor="let row of basicData; trackBy: getRowId">
  <td td-data-table-cell *ngFor="let column of columns" [numeric]="column.numeric">
    {{column.format ? column.format(row[column.name]) : row[column.name]}}
  </td>
  <td td-data-table-cell (click)="openPrompt(row, 'comments')">
    <button mat-button [class.mat-accent]="!row['comments']">{{row['comments'] || 'Add Comment'}}</button>
  </td>
</tr>
</tbody>

Et ensuite dans votre TypeScript:

getRowById(index, row) {
   // Return some unique primitive idenitifier (string, number, etc.)
   return row['some unique property'];
}

Pour plus d'informations sur trackBy, consultez:

https://netbasal.com/angular-2-improve-performance-with-trackby-cc147b5104e5https://blog.angular-university.io/angular-2-ngfor/

De plus, NGX-Datatable fonctionne très bien pour ce cas d'utilisation. Il a construit dans le défilement virtuel. https://github.com/swimlane/ngx-datatable

5
Pearman

Transférer des données dans la même variable de tableau que celle utilisée par * ngFor ne rendra pas le rendu du code HTML.

Exemple simple: https://angular-frjdnf.stackblitz.io

Modifier:

J'ai créé un exemple de projet avec une table covalente à l'aide de * ngFor avec une mise à jour angulaire de la ligne supplémentaire uniquement, sans refaire le rendu de la table entière.

Lien vers Exemple de projet Stackblitz.io .

HTML

<button (click)="addData()">Add Data</button>
<table td-data-table>
    <thead>
    <tr td-data-table-column-row>
      <td td-data-table-column *ngFor="let column of columns">
        {{column.label}}
      </td>
    </tr>
    </thead>
    <tbody>
    <tr td-data-table-row *ngFor="let row of basicData">
      <td td-data-table-cell *ngFor="let column of columns">
        {{ row[column.name] }}
      </td>
    </tr>
    </tbody>
  </table>

TS

basicData a les données initiales qui ont été chargées dans la table et je ne fais que pousser des données factices en cliquant sur le bouton "Ajouter des données" sur la basicData afin de tester la barre de défilement.

import { Component } from '@angular/core';
import { ITdDataTableColumn } from '@covalent/core/data-table';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  columns: ITdDataTableColumn[] = [
    { name: 'first_name',  label: 'First Name' },
    { name: 'last_name', label: 'Last Name' },
    { name: 'gender', label: 'Gender' }
  ];

  count = 0;

  basicData: any[] = [
    {
      "first_name": "Sully",
      "gender": "Male",
      "last_name": "Clutterham"
    },
    ...
  ]

  additionalData: any[] = [
    {
      "first_name": "Sully",
      "gender": "Male",
      "last_name": "Clutterham"
    },
    ...
  ]

  addData(){
    if(this.count >= this.additionalData.length)
      this.count = 0;

    this.basicData.Push(this.additionalData[this.count]);
    this.count++;
  }

}

J'espère que cela t'aides.

0
gowtham raj j

Il semble que lorsque vous obtenez plus de données, vous actualisez la liste entière (le tableau utilisé dans * ngFor), de sorte que angular redessine à nouveau le tableau complet. Essayez de transmettre uniquement les données de différence à ce tableau.

0
Pradeep