web-dev-qa-db-fra.com

Bootstrap 4 Table sensible, défilement horizontal et vertical

J'utilise des tables d'amorçage avec Angular 6 dans un projet et j'ai pu créer un corps de table de défilement vertical avec ce code:

<table class="table table-striped table-bordered" style="margin-bottom: 0">
      <thead> <!-- Column names -->
        <tr>
          <th scope="col">#</th>
          <th scope="col">Col 1</th>
          <th scope="col">Col 2</th>
          <th scope="col">Col 3</th>
          ...
          <th scope="col">Col N</th>
        </tr>
      </thead>
      <tbody> <!-- Data -->
        <tr>
          <th scope="row">1</th>
          <td>AAAAA</td>
          <td>BBBBB</td>
          <td>CCCCC</td>
          ...
          <td>DDDDD</td>
        </tr>
        <tr>
          <th scope="row">2</th>
          <td>AAAAA</td>
          <td>BBBBB</td>
          <td>CCCCC</td>
          ...
          <td>DDDDD</td>
        </tr>
        ...
        <tr>
          <th scope="row">n</th>
          <td>AAAAA</td>
          <td>BBBBB</td>
          <td>CCCCC</td>
          ...
          <td>DDDDD</td>
        </tr>
      </tbody>
    </table>

Et css:

  tbody {
      display:block;
      max-height:500px;
      overflow-y:auto;
  }
  thead, tbody tr {
      display:table;
      width:100%;
      table-layout:fixed;
  }
  thead {
      width: calc( 100% - 1em )
  } 

Mais maintenant, s'il y a beaucoup de colonnes, ça n'a pas l'air bien.

 // pic

Donc, je voulais aussi ajouter un défilement horizontal afin de pouvoir faire défiler le tableau complet horizontalement et uniquement le corps du tableau verticalement . Pour faire le défilement horizontal, j'ai utilisé .table-responsive comme ceci:

<div class="table-responsive">
    <table class="table table-striped table-bordered" style="margin-bottom: 0">
    ...
    </table>
</div>

Mais cela ne fonctionne que sans la partie de défilement vertical dans le fichier css.

 enter image description here

Je souhaite combiner ces deux manières de faire défiler le tableau ..__ J'ai modifié les valeurs de largeur de la partie css, de 100% à des valeurs px statiques comme ceci:

...
thead, tbody tr {
      display:table;
      width: 2000px;
      table-layout:fixed;
  }
  thead {
      width: calc( 2000px - 1em )
  } 

Et cela a fonctionné, mais je dois définir une largeur statique et je ne sais pas comment le faire de manière dynamique (en fonction du nombre de colonnes).

 enter image description here

2
JCAguilera

Je l'ai corrigé comme ceci: j'ai d'abord édité le css, puis j'ai supprimé la partie thead et ajouté du contenu dans le corps comme ceci:

body {
  --table-width: 100%; /* Or any value, this will change dinamically */
}
tbody {
  display:block;
  max-height:500px;
  overflow-y:auto;
}
thead, tbody tr {
  display:table;
  width: var(--table-width);
  table-layout:fixed;
}

J'ai aussi quitté le .table-responsive div:

<div class="table-responsive">
    <table class="table table-striped table-bordered" style="margin-bottom: 0">
    ...
    </table>
</div>

Ensuite, j'ai calculé --table-width en fonction du nombre de colonnes et de la longueur du nom de colonne le plus long. Je l'ai fait avec Angular, dans mon composant .ts:

calculateTableWidth() {
  // Get the table container width:
  const pageWidth = document.getElementById('tableCard').offsetWidth;
  // Get the longest column name
  const longest = this.tableColumns.sort(function (a, b) { return b.length - a.length; })[0];
  // Calculate table width
  let tableWidth = this.tableColumns.length * longest.length * 14;
  // If the width is less than the pageWidth
  if (tableWidth < (pageWidth - 10)) {
    // We set tableWidth to pageWidth - scrollbarWidth (10 in my project)
    tableWidth = pageWidth - 10;
  }
  // Then we update the --table-width variable:
  document.querySelector('body').style.cssText = '--table-width: ' + tableWidth + 'px';
}

J'ai besoin d'exécuter calculateTableWidth() au début dans ngOnInit() (ou lorsque j'ai défini le tableau tableColumns), puis lorsque je redimensionne la fenêtre:

ngOnInit() {
  this.tableColumns = this.myAppService.getTableColumnsNames();
  this.calculateTableWidth();
}

@HostListener('window:resize', ['$event'])
onResize(event: any) {
  this.calculateTableWidth();
}

Et c'est comme ça que j'ai résolu ça. Maintenant, j'ai un beau tableau, avec défilement vertical et horizontal.

1
JCAguilera

J'espère que cela aidera tout organisme à développer un en-tête de table angulaire 6 fixe

scss

// Table related css start
        .deallist-tbl {
            width: 100%;
            .table-striped>tbody>tr:nth-child(odd)>td {
                background-color: #F9F9F9;
            }
            .table-hover tbody tr:hover td {
                background-color: #0099CC;
                color: $content-text-white;
            }
            .table-hover tbody tr.active td {
                background-color: #0099CC;
                color: $content-text-white;
            }
            table {
                border-collapse: collapse;
                width: 100%;
                overflow-x: scroll;
                display: block;
            }
            thead {
                background-color: #F5F1EF;
            }
            thead,
            tbody {
                display: block;
            }
            tbody {
                overflow-y: scroll;
                overflow-x: hidden;
                height: 650px;
            }
            td {
                min-width: 90px;
                height: 30px;
                border: solid 1px $border-color;
                overflow: hidden;
                text-overflow: Ellipsis;
                max-width: 100px;
                padding: 5px 5px 5px 10px;
                &.index-clm {
                    width: 35px;
                    min-width: 35px;
                    padding: 5px;
                }
            }
            th {
                font-size: 10px;
                font-weight: bold;
                min-width: 90px;
                height: 30px;
                overflow: hidden;
                text-overflow: Ellipsis;
                text-transform: uppercase;
                max-width: 100px;
                padding: 5px 5px 6px 10px;
                border-left: solid 1px $content-text-black;
                border-top: solid 1px $border-color;
                border-bottom: solid 1px $border-color;
                &:last-child {
                    border-right: solid 1px $content-text-black;
                }
                &.index-clm {
                    width: 35px;
                    min-width: 35px;
                    padding: 5px;
                }

            }
        } // Table related css end

HTML

<table  class="table table-striped table-hover mb-0" id="dataTable" #tblDealList (scroll)="scrollHandler($event)">
          <thead [style.width.px]="tblWidth">
            <tr>
              <th class="text-center index-clm">*</th>
              <th app-sortable-column columnName="Column1">Column 1</th>
              <th app-sortable-column columnName="Column2">Column 2</th>
              <th app-sortable-column columnName="Column3">Column 3</th>
              <th app-sortable-column columnName="Column4">Column 4</th>
              <th app-sortable-column columnName="Column5">Column 5</th>
              <th app-sortable-column columnName="Column6">Column 6</th>
              <th app-sortable-column columnName="Column7">Column 7</th>
              <th app-sortable-column columnName="Column8">Column 8</th>
              <th app-sortable-column columnName="Column9">Column 9</th>
              <th app-sortable-column columnName="Column10">Column 10</th>
              <th app-sortable-column columnName="Column11">Column 11</th>
              <th app-sortable-column columnName="Column12">Column 12</th>
              <th app-sortable-column columnName="Column13">Column 13</th>
              <th app-sortable-column columnName="Column14">Column 14</th>
              <th app-sortable-column columnName="Column15">Column 15</th>
              <th app-sortable-column columnName="Column16">Column 16</th>

            </tr>
          </thead>
          <tbody [style.width.px]="tblWidth">
            <tr *ngFor="let item of dealList; let i = index" [class.active]="activeCode===i" (click)="selectDealItem(content,item, i)"
              (dblclick)="show()">
              <td class="text-center index-clm">{{item.isModified ? '*' : ''}}</td>
              <td>{{item.Column1 }}</td>
              <td>{{item.Column2 }}</td>
              <td>{{item.Column3 }}</td>
              <td>{{item.Column4 }}</td>
              <td>{{item.Column5 }}</td>
              <td>{{item.Column6 }}</td>
              <td>{{item.Column7 }}</td>
              <td>{{item.Column8 }}</td>
              <td>{{item.Column9 }}</td>
              <td>{{item.Column10 }}</td>
              <td>{{item.Column11 }}</td>
              <td>{{item.Column12 }}</td>
              <td>{{item.Column13 }}</td>
              <td>{{item.Column14 }}</td>
              <td>{{item.Column15 }}</td>
              <td>{{item.Column16 }}</td>
            </tr>

          </tbody>
        </table>

La fonction la plus importante du fichier ts est la suivante

 /**
   * set table width when scrolling
   */
  @HostListener('window:scroll', ['$event'])
  scrollHandler(event) {
    this.tblWidth = this.tblWidthInitial + event.target.scrollLeft;
  }

La largeur initiale de la table peut être calculée comme suit

  @ViewChild('tblDealList') tblDealList: ElementRef;

À l'intérieur de ngOnInit

  this.tblWidthInitial = this.tblDealList.nativeElement.offsetWidth;

Résultat final

 enter image description here

0