Django & DRF & Angular 101, 파트 3.4 : 데이터 테이블
썸머
Composant mat-table
소개
Dans cet article, nous allons nous pencher plus particulièrement sur un composant "data-table" : un tableau d'affichage de lignes / champs issus d'une API.
Ce type de "table" est souvent utilisée dans les applications afin de lister des éléments et interagir dessus.
Ce composant "data-table" aura tout un tas de fonctionnalités :
- service API générique
- affichage dynamique des colonnes d'un modèle que l'on souhaite
- tri des colonnes
- pagination
- recherche
- des boutons actions afin d'opérer une action sur une ligne de la table, par exemple : suppression, édition, etc
- la possibilité d'injecter des filtres colonnes pour filtrer les données de la table, un peu à la "Excel"
- de pouvoir injecter des composants dans les cellules de la table pour agir sur le champ affiché (par exemple, un radio bouton on/off pour activer / désactiver un livre ou de l' edit in place d'une valeur)
Quelques exemples :
On en fera une librairie Angular , 컴파일러 la librairie data-table 작성 : $ ng build data-table
컴포지트 매트 테이블
Angular material propose un composant mat-table qui permet d'afficher sous forme tabulaire des données. Elle présente l'avantage d'offrir pas mal de fonctionnalités: colonnes à afficher, tris, pagination, se basant sur une source de données.
L'inconvénient, comme tout composante avancé, est d'avoir à écrire beaucoup de code (dans la vue HTML et dans le ts, tout comme dans cet), on recopie donc souvent du code pour l'ajuster à ses besoins et on doit ré-appréhender son 활용(le comment ça fonctionne déjà), ce qui n'est parfois pas très Don't Repeat Yourself .
L'objectif est de concevoir un composant qui sera paramétrable afin de se soulager du code - répétitif - que l'on aurait à reproduire pour avoir une mat-table.
구조
La sources de données se définira grâce :
- à une liste de colonnes à afficher : columns
- optionnellement une liste d'actions possibles sur une ligne : actions
- un service qui permettra d'obtenir une liste d'éléments. Ce service dérivera d'un service générique sur un modèle précis, avec au moins une fonction qui ira chercher via une api la liste : DaoGeneric
- le selector pour son utilisation pourra ressembler à cela, dans sa version minimale, une datasource, les colonnes et les actions (l'objet doit exister mais peut être initialisé à vide : []) :
<mat-data-table
[dataSource]="dsData"
[columns]="columns"
[actions]="actions">
</mat-data-table>
매개변수
인터페이스 열 및 작업
La data-table, pour fonctionner, doit pouvoir afficher des colonnes, autrement dit, des champs de la table (renvoyés par une API), et potentiellement des action que l'on peut faire sur les lignes ramenées.
단일 콜론(ColumnDataTable) est définie par l'interface:
import {ColumnComponentItem, ComponentItem} from '../components/dynamic-core-components/component-item';
/**
* Options ouverture popin filtre colonne
*/
export interface HeaderFilterOptions {
colorIcon: 'accent' | 'primary' | 'warn';
position: 'top' | 'bottom' | 'left' | 'right';
hasBackDrop: boolean;
}
/**
* interface pour les colonnes de data-table
*/
export interface ColumnDataTable {
/* champs 'table' à afficher (et à trier le cas échéant) */
column: string;
/* composant cellule */
columnComponent?: () => ColumnComponentItem;
/* libellé de l'entête table */
header: string;
headerFun?: (row) => string;
/* composant filtre colonne dans le header */
headerComponent?: () => ComponentItem;
/* tooltip du filtre colonne */
headerFilterToolTip?: (row) => string;
/* option du filtre colonne : positionnement, couleur, fond */
headerFilterOptions?: HeaderFilterOptions;
/* fonction d'obtention de la valeur du champ pour la ligne courante */
display: (row) => any;
/* flex largeur */
flex?: number;
/* fonction d'obtention de la couleur d'affichage de la valeur du champ, optionnel, par défaut #000000 (noir) */
color?: (row) => string;
colorBackground?: (row) => string;
/* fonctions couleurs colonne entéte texte et fond */
colorHeader?: (row) => string;
colorHeaderBackground?: (row) => string;
/* tri actif ou non */
sort: boolean;
/* champ de tri si différent de columnDef, optionnel */
sortField?: string;
/* afficher ligne / colonne ? */
hidden?: boolean;
hiddenFun?: (row) => boolean;
/* afficher header / entête ? */
hiddenHeader?: () => boolean;
/* tronquer le texte de la cellule ? */
truncate?: boolean;
/* centré le texte de la cellule ? */
center?: boolean;
/* tooltip */
tooltip?: (row) => any;
}
Une action (ActionDataTable) est definie par l'interface:
/**
* interface pour les actions de data-table
*/
export interface ActionDataTable {
/* identifiant action */
label: string;
/* tooltip bouton */
tooltip: string;
/* tooltip fonction, optionnel, surcharge tooltip */
tooltipFun?: (row) => string;
/* fonction d'obtention de la couleur d'affichage de la valeur du champ, optionnel, par défaut #000000 (noir) */
color?: (row) => string;
colorBackground?: (row) => string;
/* fonctions couleurs colonne entéte texte et fond */
colorHeader?: (row) => string;
colorHeaderBackground?: (row) => string;
/* icon material */
icon: string;
/* calcul icon material, optionnel, surcharge icon */
iconFun?: (row) => string;
/* couleur icone (couleurs material : primary | accent | warn */
iconcolor?: string;
iconcolorFun?: (row) => string;
/* action (fonction) au click */
click: (row) => void;
/* flex colonne */
flex?: number;
/* afficher ligne ? */
hidden?: (row) => boolean;
/* afficher header / entête ? */
hiddenHeader?: () => boolean;
}
서비스
La data-table a besoin d'un service pour aller chercher les éléments à afficher, il suffit de surcharger DaoGeneric, notamment la method listItems(params) (pour lister ou rechercher sur un mot clé), la classe abstraite DaoGeneric est définie de la façon suivante, représente le CRUD d'une enité/modele, je n'ai gardé que ce qui nous intéresse pour lister, voir le code complet sur le dépot:
/**
* DaoGeneric : fourniture d'un CRUD sur un type T
* Utile pour le MatDataSource sur le list()
*/
export abstract class DaoGeneric<T> {
/** loading indicateur */
private loadingSubject = new BehaviorSubject<boolean>(false);
public loading$ = this.loadingSubject.asObservable();
constructor(private http: HttpClient) {}
/**
* Pour obtenir l'url "root" de l'API souhaitée
*
* Exemple : `${environment.baseUrl}/projets/categories/`;
* @return {string}
*/
abstract getRootUrl(urlApp?: string): string;
/**
* Obtient la liste d'objects T sous forme de Pagination
*
* @param {string} sort : champ de tri [optionnel]
* @param {string} order : si 'sort', ordre du tri : asc | desc [optionnel]
* @param {number} limit : nb. max d'éléments à ramener
* @param {number} offset : démarre la pagination à partir de 'offset'
* @param {Map<string, string>} extraParams : extra paramètres à passer à la requête API [optionnel]
* @param {string} keyword : mot de recherche le cas échéant (!= '') [optionnel]
* @param {Map<string, string[]>} extraDict : extra paramètres où la clé à plusieurs valeurs : key=val1&key=val2&...&key=valn
* @param {string} urlBaseOverride : url à surcharger (remplacerra getRootUrl())
* @param {boolean} withCache : accède au cache ou non
* @return {Observable<Pagination>} : un objet Pagination des éléments trouvés
*/
list(sort: string, order: string, limit: number, offset: number,
extraParams: Map<string, string> = null,
keyword = '',
extraDict: Map<string, string[]> = null,
urlBaseOverride: string = null,
withCache = false): Observable<Pagination> {
this.loadingSubject.next(true);
let params1 = this._getPaginationParams(limit, offset, keyword, extraParams);
let url = '';
if (urlBaseOverride) {
url = urlBaseOverride;
} else {
url = this.getRootUrl();
}
if (sort && sort !== '') {
params1 = this._getSorting(sort, order, params1);
}
const params = this._getUrlHttpDict(extraDict, params1);
return this.http
.get<T[]>(url, {params})
.pipe(
finalize(() => this.loadingSubject.next(false)),
map(response => this._getPagination(response, limit)));
}
/**
* Obtient la liste d'objects T sous forme de Pagination
*
* @param {ListParameters} parameters : paramètre pour l'obtention de la liste (sorting, pagination, mot de recherche, extra paramètres)
* @return {Observable<Pagination>}
*/
listItems(parameters: ListParameters): Observable<Pagination> {
return this.list(
parameters.sort, parameters.order,
parameters.limit, parameters.offset,
parameters.extraParams,
parameters.keyword,
parameters.extraDict,
parameters.urlBaseOverride,
parameters.withCache);
}
/**
* Liste de tous les éléments
*
* @param {Map<string, string>} extraParams : extra params url [optionnel]
* @param {string} keyword : mot de recherche [optionnel]
* @param {boolean} withCache : activer le cache ? [optionnel]
* @return {Observable<Pagination>}
*/
listAllItems(extraParams: Map<string, string> = null, keyword: string = '', withCache?: boolean): Observable<Pagination> {
return this.list('', '', 0, 0, extraParams, keyword, null, null, withCache);
}
//...
}
Cette classe générique pourra servir à son usage staff sur une enité pour effectuer le CRUD (Create/Read (un ou une liste)/Update (ou Patch)/Delete) et sera utile à la data-table.
Utilization de la 데이터 테이블
Utilisons la data-table pour lister les auteurs et agir dessus.
1- Service sur les auteurs, hérite de DaoGeneric, le généric est fixé sur le modele Author, on pourra profiter ainsi de toute la tuillauterie pour ajouter, modifier, supprimer ou lister des auteurs, la méthode abstraite getRootUrl()
est à implémenter, cela donne l'URL de l'API pour atteindre les auteurs :
@Injectable({ providedIn: 'root' })
export class AuthorDtService extends DaoGeneric<Author> {
private url = `${environment.baseUrl}/library/authors/`;
constructor(private httpClient: HttpClient) {
super(httpClient);
}
getRootUrl(urlApp?: string): string {
return this.url;
}
}
2- 컴포지트 AuthorDtListComponent
Création d'un composant dans lequel nous allons utiliser la data-table : recherche, afficher des colonnes et pouvoir interagir sur la cellule, des actions (suppression, édition), des filtres colonnes pour filtrer la liste
저자-dt-list.component.html :
<mat-card>
<mat-card-title>
Auteurs
<mat-card-actions align="end" style="padding-right: 10px;">
<button *ngIf="isGest()"
mat-raised-button (click)="addAuthor()">Ajouter un auteur</button>
</mat-card-actions>
<mat-card-content>
<mat-data-table
[dataSource]="dsAuthors"
[columns]="columns"
[actions]="actions"
[extraParams]="extraParams"
[placeHolderFilter]="'Rechercher sur un auteur ou sur un livre'"
[showFirstLastButtons]="true" [showLoader]="true"
[loaderMask]="true" [loaderProgress]="true">
</mat-data-table>
</mat-card-content>
</mat-card>
저자-dt-list.component.ts :
le TS dans lequel nous définissons les columns, les actions, l'injection de notre service AuthorDtService et son usage dans la data-table (via l'affectation this.dsAuthors.daoService = authorSvc;
et utilisé par l'input dataSource
dans la data-table) .
Source simplifié pour la définition des champs à afficher, les actions, le filtre colonne sur les auteurs AuthorFilterDtComponent
(doit implémenter l'interface HeaderComponent
) et le filtre livre BooksFilterDtComponent
, ainsi que le composant cellule livres BooksListColumnComponent
pour mettre à jour les livres d'un auteur.
@Component({ selector: 'app-author-dt-list',
templateUrl: './author-dt-list.component.html',
styleUrls: ['./author-dt-list.component.css']
})
export class AuthorDtListComponent implements OnInit {
columns: ColumnDataTable[] = [{
column: 'author', header: 'Auteur', sortField: 'last_name',
display: (element: Author) => `${element.first_name} ${element.last_name}`,
tooltip: (row: Author) => `${row.first_name} ${row.last_name}`,
headerFilterToolTip: (row) => 'Filtrer sur l\'auteur',
headerFilterOptions: {colorIcon: 'warn', hasBackDrop: true, position: 'right'} as HeaderFilterOptions,
flex: 20, sort: true
},
{
column: 'books', header: 'Livres',
display: (element: Author) => this.getBooks(element),
tooltip: (row: Author) => this.getBooks(row),
headerFilterToolTip: (row) => 'Filtrer sur un livre',
sort: false
}];
actions: ActionDataTable[] = [{
label: 'delete', tooltip: 'Supprimer l\'auteur', icon: 'delete',
click: (row: Author) => this.deleteAuthor(row),
iconcolor: 'warn',
},
{
label: 'edit', tooltip: 'Modifier l\'auteur', icon: 'edit',
click: (row: Author) => this.editAuthor(row),
iconcolor: 'accent',
}];
dsAuthors: MatDataSourceGeneric<Author> = new MatDataSourceGeneric<Author>();
/**
* Paramétres de filtrage sur l'API DaoService.listItems(params)
*/
extraParams: Map<string, string> = new Map<string, string>();
/**
* les valeurs possibles pour les listes des filtres colonnes : id / chaîne à afficher
*/
filterColumns: Map<string, Map<string, string>> = new Map<string, Map<string, string>>();
@ViewChild(DataTableComponent, {static: false}) matDataTable: DataTableComponent;
constructor(private dataTableHeaderSvc: DataTableHeaderColumnComponentService,
private authorSvc: AuthorDtService) {
this.dsAuthors.daoService = authorSvc;
}
ngOnInit(): void {
this._setFilterAuthor();
this._setFilterBook();
}
/**
* Initialisation du filtre colonne sur les auteurs
*/
_setFilterAuthor() {
this.subSink.sink = this.authorSvc
.listAllItems()
.subscribe((authors: Pagination) => {
const listAuthors = new Map<string, string>();
(authors.list as Author[])
.forEach((author) => listAuthors.set(author.id.toString(), `${author.first_name} ${author.last_name}`));
this.filterColumns.set('author', listAuthors);
this._setAuthorFilter('author', 'sur un auteur', 'id',
'Filtrer par un auteur', 'Auteur', () => this.matDataTable.reload());
});
}
/**
* Création du component colonne filtre Author
*/
private _setAuthorFilter(listName, listLabel, keyFilter, placeHolder, condName, callBack: () => void = null) {
const data = {
placeHolder, keyFilter,
filterColumns: this._getValuesMap(listName),
filterName: condName
};
const filterComponent = this.dataTableHeaderSvc.createHeaderComponent(
this.columns, listName, `author_filter_list_${listName}`, `${listLabel}`, AuthorFilterDtComponent, data, true);
if (filterComponent) {
this.subSink.sink = filterComponent.subject$.subscribe((d) => {
if (d && d.key) {
filterComponent.dataDefault = {id: d.value};
if (this.extraParams.get(d.key)) {
this.extraParams.delete(d.key);
}
if (d.value === 0 || d.value === '0') {
this.extraParams.delete(d.key);
} else {
this.extraParams.set(d.key, d.value);
}
if (callBack) {
callBack.call(null, null);
}
}
});
}
}
/**
* Obtention d'un dico key / value à partir de filterColumns: Map<string, Map<string, string>>
* @param {string} key : sur cette clé
*/
private _getValuesMap(key: string): Map<string, string> {
if (this.filterColumns.has(key)) {
return this.filterColumns.get(key);
}
return new Map<string, string>();
}
/**
* Initialisation du filtre colonne sur les livres
* Ajout instance composant cellule sur les livres d'un auteur
*/
_setFilterBook() {
this.subSink.sink = this.bookSvc
.listAllItems()
.subscribe((books: Pagination) => {
const listBooks = new Map<string, string>();
(books.list as Book[])
.forEach((book) => listBooks.set(book.id.toString(), `${book.name}`));
this.filterColumns.set('books', listBooks);
this._setBookFilter('books', 'sur un livre', 'book',
'Filtrer par un livre', 'Livre', () => this.matDataTable.reload());
this._setAuthorDynamicComponent('books', 'auteur', 'book');
});
}
/**
* Initialisation du composant sur la cellule livre : livres à choisir pour l'auteur de la ligne courante
*/
private _setAuthorDynamicComponent(listName, listLabel, keyFilter, callBack: () => void = null) {
const data = {
filterColumns: this._getValuesMap(listName),
};
const filterComponent = this.dataTableHeaderSvc
.createColumnComponent(
this.columns, listName, `books_list_${listName}`, `${listLabel}`,
BooksListColumnComponent, data);
if (filterComponent) {
filterComponent.subject$.subscribe((_data) => {
this.matDataTable.reload();
});
}
}
결론 및 소스
Dans cet article, nous avons vu comment encapsuler afin de mutualiser et son code d'usage le composant Material mat-table en y apportant des fonctionnalités de bases : filtres colonnes, composants cellules, actions, recherche, tris et pagination.
Retrouvez les sources de cet article (backend et frontend) sur https://github.com/zorky/library/tree/django-drf-angular-3.4
Reference
이 문제에 관하여(Django & DRF & Angular 101, 파트 3.4 : 데이터 테이블), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://dev.to/zorky/django-drf-angular-101-partie-3-4-4h7h
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
L'inconvénient, comme tout composante avancé, est d'avoir à écrire beaucoup de code (dans la vue HTML et dans le ts, tout comme dans cet), on recopie donc souvent du code pour l'ajuster à ses besoins et on doit ré-appréhender son 활용(le comment ça fonctionne déjà), ce qui n'est parfois pas très Don't Repeat Yourself .
L'objectif est de concevoir un composant qui sera paramétrable afin de se soulager du code - répétitif - que l'on aurait à reproduire pour avoir une mat-table.
구조
La sources de données se définira grâce :
- à une liste de colonnes à afficher : columns
- optionnellement une liste d'actions possibles sur une ligne : actions
- un service qui permettra d'obtenir une liste d'éléments. Ce service dérivera d'un service générique sur un modèle précis, avec au moins une fonction qui ira chercher via une api la liste : DaoGeneric
- le selector pour son utilisation pourra ressembler à cela, dans sa version minimale, une datasource, les colonnes et les actions (l'objet doit exister mais peut être initialisé à vide : []) :
<mat-data-table
[dataSource]="dsData"
[columns]="columns"
[actions]="actions">
</mat-data-table>
매개변수
인터페이스 열 및 작업
La data-table, pour fonctionner, doit pouvoir afficher des colonnes, autrement dit, des champs de la table (renvoyés par une API), et potentiellement des action que l'on peut faire sur les lignes ramenées.
단일 콜론(ColumnDataTable) est définie par l'interface:
import {ColumnComponentItem, ComponentItem} from '../components/dynamic-core-components/component-item';
/**
* Options ouverture popin filtre colonne
*/
export interface HeaderFilterOptions {
colorIcon: 'accent' | 'primary' | 'warn';
position: 'top' | 'bottom' | 'left' | 'right';
hasBackDrop: boolean;
}
/**
* interface pour les colonnes de data-table
*/
export interface ColumnDataTable {
/* champs 'table' à afficher (et à trier le cas échéant) */
column: string;
/* composant cellule */
columnComponent?: () => ColumnComponentItem;
/* libellé de l'entête table */
header: string;
headerFun?: (row) => string;
/* composant filtre colonne dans le header */
headerComponent?: () => ComponentItem;
/* tooltip du filtre colonne */
headerFilterToolTip?: (row) => string;
/* option du filtre colonne : positionnement, couleur, fond */
headerFilterOptions?: HeaderFilterOptions;
/* fonction d'obtention de la valeur du champ pour la ligne courante */
display: (row) => any;
/* flex largeur */
flex?: number;
/* fonction d'obtention de la couleur d'affichage de la valeur du champ, optionnel, par défaut #000000 (noir) */
color?: (row) => string;
colorBackground?: (row) => string;
/* fonctions couleurs colonne entéte texte et fond */
colorHeader?: (row) => string;
colorHeaderBackground?: (row) => string;
/* tri actif ou non */
sort: boolean;
/* champ de tri si différent de columnDef, optionnel */
sortField?: string;
/* afficher ligne / colonne ? */
hidden?: boolean;
hiddenFun?: (row) => boolean;
/* afficher header / entête ? */
hiddenHeader?: () => boolean;
/* tronquer le texte de la cellule ? */
truncate?: boolean;
/* centré le texte de la cellule ? */
center?: boolean;
/* tooltip */
tooltip?: (row) => any;
}
Une action (ActionDataTable) est definie par l'interface:
/**
* interface pour les actions de data-table
*/
export interface ActionDataTable {
/* identifiant action */
label: string;
/* tooltip bouton */
tooltip: string;
/* tooltip fonction, optionnel, surcharge tooltip */
tooltipFun?: (row) => string;
/* fonction d'obtention de la couleur d'affichage de la valeur du champ, optionnel, par défaut #000000 (noir) */
color?: (row) => string;
colorBackground?: (row) => string;
/* fonctions couleurs colonne entéte texte et fond */
colorHeader?: (row) => string;
colorHeaderBackground?: (row) => string;
/* icon material */
icon: string;
/* calcul icon material, optionnel, surcharge icon */
iconFun?: (row) => string;
/* couleur icone (couleurs material : primary | accent | warn */
iconcolor?: string;
iconcolorFun?: (row) => string;
/* action (fonction) au click */
click: (row) => void;
/* flex colonne */
flex?: number;
/* afficher ligne ? */
hidden?: (row) => boolean;
/* afficher header / entête ? */
hiddenHeader?: () => boolean;
}
서비스
La data-table a besoin d'un service pour aller chercher les éléments à afficher, il suffit de surcharger DaoGeneric, notamment la method listItems(params) (pour lister ou rechercher sur un mot clé), la classe abstraite DaoGeneric est définie de la façon suivante, représente le CRUD d'une enité/modele, je n'ai gardé que ce qui nous intéresse pour lister, voir le code complet sur le dépot:
/**
* DaoGeneric : fourniture d'un CRUD sur un type T
* Utile pour le MatDataSource sur le list()
*/
export abstract class DaoGeneric<T> {
/** loading indicateur */
private loadingSubject = new BehaviorSubject<boolean>(false);
public loading$ = this.loadingSubject.asObservable();
constructor(private http: HttpClient) {}
/**
* Pour obtenir l'url "root" de l'API souhaitée
*
* Exemple : `${environment.baseUrl}/projets/categories/`;
* @return {string}
*/
abstract getRootUrl(urlApp?: string): string;
/**
* Obtient la liste d'objects T sous forme de Pagination
*
* @param {string} sort : champ de tri [optionnel]
* @param {string} order : si 'sort', ordre du tri : asc | desc [optionnel]
* @param {number} limit : nb. max d'éléments à ramener
* @param {number} offset : démarre la pagination à partir de 'offset'
* @param {Map<string, string>} extraParams : extra paramètres à passer à la requête API [optionnel]
* @param {string} keyword : mot de recherche le cas échéant (!= '') [optionnel]
* @param {Map<string, string[]>} extraDict : extra paramètres où la clé à plusieurs valeurs : key=val1&key=val2&...&key=valn
* @param {string} urlBaseOverride : url à surcharger (remplacerra getRootUrl())
* @param {boolean} withCache : accède au cache ou non
* @return {Observable<Pagination>} : un objet Pagination des éléments trouvés
*/
list(sort: string, order: string, limit: number, offset: number,
extraParams: Map<string, string> = null,
keyword = '',
extraDict: Map<string, string[]> = null,
urlBaseOverride: string = null,
withCache = false): Observable<Pagination> {
this.loadingSubject.next(true);
let params1 = this._getPaginationParams(limit, offset, keyword, extraParams);
let url = '';
if (urlBaseOverride) {
url = urlBaseOverride;
} else {
url = this.getRootUrl();
}
if (sort && sort !== '') {
params1 = this._getSorting(sort, order, params1);
}
const params = this._getUrlHttpDict(extraDict, params1);
return this.http
.get<T[]>(url, {params})
.pipe(
finalize(() => this.loadingSubject.next(false)),
map(response => this._getPagination(response, limit)));
}
/**
* Obtient la liste d'objects T sous forme de Pagination
*
* @param {ListParameters} parameters : paramètre pour l'obtention de la liste (sorting, pagination, mot de recherche, extra paramètres)
* @return {Observable<Pagination>}
*/
listItems(parameters: ListParameters): Observable<Pagination> {
return this.list(
parameters.sort, parameters.order,
parameters.limit, parameters.offset,
parameters.extraParams,
parameters.keyword,
parameters.extraDict,
parameters.urlBaseOverride,
parameters.withCache);
}
/**
* Liste de tous les éléments
*
* @param {Map<string, string>} extraParams : extra params url [optionnel]
* @param {string} keyword : mot de recherche [optionnel]
* @param {boolean} withCache : activer le cache ? [optionnel]
* @return {Observable<Pagination>}
*/
listAllItems(extraParams: Map<string, string> = null, keyword: string = '', withCache?: boolean): Observable<Pagination> {
return this.list('', '', 0, 0, extraParams, keyword, null, null, withCache);
}
//...
}
Cette classe générique pourra servir à son usage staff sur une enité pour effectuer le CRUD (Create/Read (un ou une liste)/Update (ou Patch)/Delete) et sera utile à la data-table.
Utilization de la 데이터 테이블
Utilisons la data-table pour lister les auteurs et agir dessus.
1- Service sur les auteurs, hérite de DaoGeneric, le généric est fixé sur le modele Author, on pourra profiter ainsi de toute la tuillauterie pour ajouter, modifier, supprimer ou lister des auteurs, la méthode abstraite
getRootUrl()
est à implémenter, cela donne l'URL de l'API pour atteindre les auteurs :@Injectable({ providedIn: 'root' })
export class AuthorDtService extends DaoGeneric<Author> {
private url = `${environment.baseUrl}/library/authors/`;
constructor(private httpClient: HttpClient) {
super(httpClient);
}
getRootUrl(urlApp?: string): string {
return this.url;
}
}
2- 컴포지트 AuthorDtListComponent
Création d'un composant dans lequel nous allons utiliser la data-table : recherche, afficher des colonnes et pouvoir interagir sur la cellule, des actions (suppression, édition), des filtres colonnes pour filtrer la liste
저자-dt-list.component.html :
<mat-card>
<mat-card-title>
Auteurs
<mat-card-actions align="end" style="padding-right: 10px;">
<button *ngIf="isGest()"
mat-raised-button (click)="addAuthor()">Ajouter un auteur</button>
</mat-card-actions>
<mat-card-content>
<mat-data-table
[dataSource]="dsAuthors"
[columns]="columns"
[actions]="actions"
[extraParams]="extraParams"
[placeHolderFilter]="'Rechercher sur un auteur ou sur un livre'"
[showFirstLastButtons]="true" [showLoader]="true"
[loaderMask]="true" [loaderProgress]="true">
</mat-data-table>
</mat-card-content>
</mat-card>
저자-dt-list.component.ts :
le TS dans lequel nous définissons les columns, les actions, l'injection de notre service AuthorDtService et son usage dans la data-table (via l'affectation
this.dsAuthors.daoService = authorSvc;
et utilisé par l'input dataSource
dans la data-table) .Source simplifié pour la définition des champs à afficher, les actions, le filtre colonne sur les auteurs
AuthorFilterDtComponent
(doit implémenter l'interface HeaderComponent
) et le filtre livre BooksFilterDtComponent
, ainsi que le composant cellule livres BooksListColumnComponent
pour mettre à jour les livres d'un auteur.@Component({ selector: 'app-author-dt-list',
templateUrl: './author-dt-list.component.html',
styleUrls: ['./author-dt-list.component.css']
})
export class AuthorDtListComponent implements OnInit {
columns: ColumnDataTable[] = [{
column: 'author', header: 'Auteur', sortField: 'last_name',
display: (element: Author) => `${element.first_name} ${element.last_name}`,
tooltip: (row: Author) => `${row.first_name} ${row.last_name}`,
headerFilterToolTip: (row) => 'Filtrer sur l\'auteur',
headerFilterOptions: {colorIcon: 'warn', hasBackDrop: true, position: 'right'} as HeaderFilterOptions,
flex: 20, sort: true
},
{
column: 'books', header: 'Livres',
display: (element: Author) => this.getBooks(element),
tooltip: (row: Author) => this.getBooks(row),
headerFilterToolTip: (row) => 'Filtrer sur un livre',
sort: false
}];
actions: ActionDataTable[] = [{
label: 'delete', tooltip: 'Supprimer l\'auteur', icon: 'delete',
click: (row: Author) => this.deleteAuthor(row),
iconcolor: 'warn',
},
{
label: 'edit', tooltip: 'Modifier l\'auteur', icon: 'edit',
click: (row: Author) => this.editAuthor(row),
iconcolor: 'accent',
}];
dsAuthors: MatDataSourceGeneric<Author> = new MatDataSourceGeneric<Author>();
/**
* Paramétres de filtrage sur l'API DaoService.listItems(params)
*/
extraParams: Map<string, string> = new Map<string, string>();
/**
* les valeurs possibles pour les listes des filtres colonnes : id / chaîne à afficher
*/
filterColumns: Map<string, Map<string, string>> = new Map<string, Map<string, string>>();
@ViewChild(DataTableComponent, {static: false}) matDataTable: DataTableComponent;
constructor(private dataTableHeaderSvc: DataTableHeaderColumnComponentService,
private authorSvc: AuthorDtService) {
this.dsAuthors.daoService = authorSvc;
}
ngOnInit(): void {
this._setFilterAuthor();
this._setFilterBook();
}
/**
* Initialisation du filtre colonne sur les auteurs
*/
_setFilterAuthor() {
this.subSink.sink = this.authorSvc
.listAllItems()
.subscribe((authors: Pagination) => {
const listAuthors = new Map<string, string>();
(authors.list as Author[])
.forEach((author) => listAuthors.set(author.id.toString(), `${author.first_name} ${author.last_name}`));
this.filterColumns.set('author', listAuthors);
this._setAuthorFilter('author', 'sur un auteur', 'id',
'Filtrer par un auteur', 'Auteur', () => this.matDataTable.reload());
});
}
/**
* Création du component colonne filtre Author
*/
private _setAuthorFilter(listName, listLabel, keyFilter, placeHolder, condName, callBack: () => void = null) {
const data = {
placeHolder, keyFilter,
filterColumns: this._getValuesMap(listName),
filterName: condName
};
const filterComponent = this.dataTableHeaderSvc.createHeaderComponent(
this.columns, listName, `author_filter_list_${listName}`, `${listLabel}`, AuthorFilterDtComponent, data, true);
if (filterComponent) {
this.subSink.sink = filterComponent.subject$.subscribe((d) => {
if (d && d.key) {
filterComponent.dataDefault = {id: d.value};
if (this.extraParams.get(d.key)) {
this.extraParams.delete(d.key);
}
if (d.value === 0 || d.value === '0') {
this.extraParams.delete(d.key);
} else {
this.extraParams.set(d.key, d.value);
}
if (callBack) {
callBack.call(null, null);
}
}
});
}
}
/**
* Obtention d'un dico key / value à partir de filterColumns: Map<string, Map<string, string>>
* @param {string} key : sur cette clé
*/
private _getValuesMap(key: string): Map<string, string> {
if (this.filterColumns.has(key)) {
return this.filterColumns.get(key);
}
return new Map<string, string>();
}
/**
* Initialisation du filtre colonne sur les livres
* Ajout instance composant cellule sur les livres d'un auteur
*/
_setFilterBook() {
this.subSink.sink = this.bookSvc
.listAllItems()
.subscribe((books: Pagination) => {
const listBooks = new Map<string, string>();
(books.list as Book[])
.forEach((book) => listBooks.set(book.id.toString(), `${book.name}`));
this.filterColumns.set('books', listBooks);
this._setBookFilter('books', 'sur un livre', 'book',
'Filtrer par un livre', 'Livre', () => this.matDataTable.reload());
this._setAuthorDynamicComponent('books', 'auteur', 'book');
});
}
/**
* Initialisation du composant sur la cellule livre : livres à choisir pour l'auteur de la ligne courante
*/
private _setAuthorDynamicComponent(listName, listLabel, keyFilter, callBack: () => void = null) {
const data = {
filterColumns: this._getValuesMap(listName),
};
const filterComponent = this.dataTableHeaderSvc
.createColumnComponent(
this.columns, listName, `books_list_${listName}`, `${listLabel}`,
BooksListColumnComponent, data);
if (filterComponent) {
filterComponent.subject$.subscribe((_data) => {
this.matDataTable.reload();
});
}
}
결론 및 소스
Dans cet article, nous avons vu comment encapsuler afin de mutualiser et son code d'usage le composant Material mat-table en y apportant des fonctionnalités de bases : filtres colonnes, composants cellules, actions, recherche, tris et pagination.
Retrouvez les sources de cet article (backend et frontend) sur https://github.com/zorky/library/tree/django-drf-angular-3.4
Reference
이 문제에 관하여(Django & DRF & Angular 101, 파트 3.4 : 데이터 테이블), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://dev.to/zorky/django-drf-angular-101-partie-3-4-4h7h
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
Reference
이 문제에 관하여(Django & DRF & Angular 101, 파트 3.4 : 데이터 테이블), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/zorky/django-drf-angular-101-partie-3-4-4h7h텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)