parent
56b19f8a0b
commit
851ee9e637
@ -0,0 +1,14 @@ |
||||
<button (click)="$event.stopPropagation();" mat-icon-button [matMenuTriggerFor]="menu" aria-label="filter-button avec menu"> |
||||
<mat-icon>filter_alt</mat-icon> |
||||
</button> |
||||
<mat-menu #menu="matMenu"> |
||||
<mat-list role="list" (click)="$event.stopPropagation();"> |
||||
<mat-list-item role="listitem"> |
||||
<mat-checkbox (change)="selectedAllChecked($event.checked)" [checked]="checkedAll"> Tout sélectionner</mat-checkbox> |
||||
</mat-list-item> |
||||
<mat-list-item *ngFor="let data of dataSource" role="listitem"> |
||||
<mat-checkbox *ngIf="isPropertyValueName" (change)="selectedChecked($event.checked,data)" [checked]="exists(data)"> {{data[propertyValueName]}}</mat-checkbox> |
||||
<mat-checkbox *ngIf="!isPropertyValueName" (change)="selectedChecked($event.checked,data)" [checked]="exists(data)"> {{data}}</mat-checkbox> |
||||
</mat-list-item> |
||||
</mat-list> |
||||
</mat-menu> |
@ -0,0 +1,120 @@ |
||||
import { Component, Input, Output, EventEmitter, OnInit, OnChanges } from "@angular/core"; |
||||
|
||||
import { SelectedElement } from "@shared/filter/selected-element"; |
||||
|
||||
|
||||
|
||||
|
||||
@Component({ |
||||
selector: "checkbox-filter", |
||||
templateUrl: "./checkbox-filter.html", |
||||
styleUrls: ["./checkbox-filter.css"] |
||||
}) |
||||
export class CheckboxFilterComponent<T> implements OnInit, OnChanges { |
||||
|
||||
/** |
||||
* Liste des éléments sélectionnés |
||||
*/ |
||||
elementsSelected: Array<T> = []; |
||||
|
||||
/** |
||||
* Booléen permettant de determiner si la propriété "propertyValueName" contient une valeur ou non |
||||
*/ |
||||
isPropertyValueName: boolean; |
||||
|
||||
/** |
||||
* Coche toutes les cases à cocher |
||||
*/ |
||||
@Input() checkedAll: boolean; |
||||
|
||||
/** |
||||
* Source de données |
||||
*/ |
||||
@Input() dataSource : Array<T>; |
||||
|
||||
/** |
||||
* Nom de la propriété contenant la valeur à afficher |
||||
*/ |
||||
@Input() propertyValueName: string;
|
||||
|
||||
/** |
||||
* Booléen permettant de savoir si toutes les cases sont cochées ou non |
||||
*/ |
||||
@Output() isSelectedAllEvent = new EventEmitter<boolean>(); |
||||
|
||||
/** |
||||
* Elément sélectionné |
||||
*/ |
||||
@Output() isSelectedEvent = new EventEmitter<SelectedElement<T>>(); |
||||
|
||||
|
||||
constructor() {} |
||||
|
||||
ngOnInit() { |
||||
this.isPropertyValueName = !this.propertyValueName ? false : true; |
||||
} |
||||
|
||||
ngOnChanges() { |
||||
if (this.dataSource.length > 0) { |
||||
this.checkElementhasProperty(); |
||||
this.selectedAllChecked(this.checkedAll); |
||||
}
|
||||
} |
||||
|
||||
|
||||
/** |
||||
* Vérifie que tous les éléments de source de données possède la propriété "propertyValueName" lorsque cette dernière
|
||||
* contient une valeur. |
||||
*/ |
||||
checkElementhasProperty() { |
||||
if(this.propertyValueName && !this.dataSource.every(e => e.hasOwnProperty(this.propertyValueName))) |
||||
throw new Error("Il existe au moins un élément dans la source de données qui ne possède pas la propriété '"+this.propertyValueName+"'.");
|
||||
} |
||||
|
||||
|
||||
/** |
||||
* Détermine si l'élément est présent dans la liste des éléments sélectionnés |
||||
* @param element
|
||||
*/ |
||||
exists(element) { |
||||
return this.elementsSelected.indexOf(element) > -1; |
||||
}; |
||||
|
||||
/** |
||||
* Met à jour la liste des éléments sélectionnés et met à jour l'EventEmitter "isSelectedAllEvent" |
||||
* @param event case "Tout Sélectionner" cochée ou décochée |
||||
*/ |
||||
selectedAllChecked(event) { |
||||
this.isSelectedAllEvent.emit(event);
|
||||
this.checkedAll = event; |
||||
this.elementsSelected = []; |
||||
|
||||
if(event) |
||||
this.dataSource.map(data => this.elementsSelected.push(data)); |
||||
} |
||||
|
||||
/** |
||||
* Met à jour la liste des éléments sélectionnés et met à jour l'EventEmitter "isSelectedEvent" |
||||
* @param event case cochée ou décochée par l'utilisateur |
||||
* @param data Valeur de la case cochée ou décochée |
||||
*/ |
||||
selectedChecked = (event: any, data: T) => { |
||||
this.isSelectedEvent.emit({isSelected: event, selectedElement: data}); |
||||
|
||||
// si la checkbox a été cochée
|
||||
if(event) |
||||
this.elementsSelected.push(data); |
||||
else |
||||
this.elementsSelected = this.elementsSelected.filter(element => element != data); |
||||
|
||||
// coche la case "Tout sélectionner" si tous les éléments sont cochés
|
||||
this.elementsSelected.length == this.dataSource.length ? this.checkedAll = true: this.checkedAll = false; |
||||
} |
||||
|
||||
/** |
||||
* Une fois la page fermée, il est nécessaire de se désabonner des Oberservable afin d'éviter les fuites mémoires. |
||||
*/ |
||||
ngOnDestroy() { |
||||
} |
||||
} |
||||
|
@ -0,0 +1,28 @@ |
||||
import { NgModule } from "@angular/core"; |
||||
import { CommonModule } from '@angular/common'; |
||||
import { FormsModule, ReactiveFormsModule} from '@angular/forms'; |
||||
import { RouterModule } from '@angular/router'; |
||||
|
||||
import { MaterialModule } from "../angular-material/angular-material.module"; |
||||
import { CheckboxFilterComponent } from "@shared/filter/checkbox-filter/checkbox-filter"; |
||||
import { SelectFilterComponent } from "@shared/filter/select-filter/select-filter"; |
||||
|
||||
|
||||
@NgModule({ |
||||
declarations: [
|
||||
CheckboxFilterComponent, |
||||
SelectFilterComponent |
||||
], |
||||
imports: [ |
||||
MaterialModule, |
||||
CommonModule, |
||||
FormsModule, |
||||
ReactiveFormsModule, |
||||
RouterModule |
||||
], |
||||
exports: [ |
||||
CheckboxFilterComponent, |
||||
SelectFilterComponent |
||||
] |
||||
}) |
||||
export class FilterModule {} |
@ -0,0 +1,4 @@ |
||||
mat-select .mat-checkbox-layout, |
||||
mat-select .mat-checkbox-label { |
||||
width:100% !important; |
||||
} |
@ -0,0 +1,11 @@ |
||||
<mat-form-field appearance="fill"> |
||||
<mat-label>{{label}}</mat-label> |
||||
<mat-select [(value)]="elementsSelected" multiple> |
||||
<mat-checkbox class="mat-option" (change)="selectedAllChecked($event.checked)" [checked]="checkedAll"> Tout sélectionner</mat-checkbox> |
||||
<ng-container *ngFor="let data of dataSource"> |
||||
<mat-option #matOption *ngIf="isPropertyValueName" (click)="selectedChecked(matOption.selected, data)" [value]="data">{{data[propertyValueName]}}</mat-option> |
||||
<mat-option #matOption *ngIf="!isPropertyValueName" (click)="selectedChecked(matOption.selected, data)" [value]="data">{{data}}</mat-option> |
||||
</ng-container> |
||||
</mat-select> |
||||
</mat-form-field> |
||||
|
@ -0,0 +1,116 @@ |
||||
import { Component, Input, Output, EventEmitter, OnInit, OnChanges } from "@angular/core"; |
||||
import { SelectedElement } from "@shared/filter/selected-element"; |
||||
|
||||
@Component({ |
||||
selector: "select-filter", |
||||
templateUrl: "./select-filter.html", |
||||
styleUrls: ["./select-filter.css"] |
||||
}) |
||||
export class SelectFilterComponent<T> implements OnInit, OnChanges { |
||||
|
||||
/** |
||||
* Liste des éléments sélectionnés |
||||
*/ |
||||
elementsSelected: Array<T> = []; |
||||
|
||||
/** |
||||
* Booléen permettant de determiner si la propriété "propertyValueName" contient une valeur ou non |
||||
*/ |
||||
isPropertyValueName: boolean; |
||||
|
||||
/** |
||||
* Libellé qui est affiché dans la liste déroulante lorsqu'aucune valeur n'est sélectionnée |
||||
*/ |
||||
@Input() label: string; |
||||
|
||||
/** |
||||
* Cocher toutes les cases à cocher |
||||
*/ |
||||
@Input() checkedAll: boolean; |
||||
|
||||
/** |
||||
* Source de données |
||||
*/ |
||||
@Input() dataSource : Array<T>; |
||||
|
||||
/** |
||||
* Nom de la propriété contenant la valeur à afficher |
||||
*/ |
||||
@Input() propertyValueName: string;
|
||||
|
||||
/** |
||||
* Booléen permettant de savoir si toutes les cases sont cochées ou non |
||||
*/ |
||||
@Output() isSelectedAllEvent = new EventEmitter<boolean>(); |
||||
|
||||
/** |
||||
* Elément sélectionné |
||||
*/ |
||||
@Output() isSelectedEvent = new EventEmitter<SelectedElement<T>>(); |
||||
|
||||
|
||||
constructor() {} |
||||
|
||||
ngOnInit() { |
||||
this.isPropertyValueName = !this.propertyValueName ? false : true; |
||||
} |
||||
|
||||
ngOnChanges() { |
||||
if (this.dataSource.length > 0) { |
||||
this.checkElementhasProperty();
|
||||
this.selectedAllChecked(this.checkedAll); |
||||
}
|
||||
} |
||||
|
||||
|
||||
/** |
||||
* Vérifie que tous les éléments de source de données possède la propriété "propertyValueName" lorsque cette dernière
|
||||
* contient une valeur. |
||||
*/ |
||||
checkElementhasProperty() { |
||||
if(this.propertyValueName && !this.dataSource.every(e => e.hasOwnProperty(this.propertyValueName))) |
||||
throw new Error("Il existe au moins un élément dans la source de données qui ne possède pas la propriété '"+this.propertyValueName+"'.");
|
||||
} |
||||
|
||||
/** |
||||
* Met à jour la liste des éléments sélectionnés et met à jour l'EventEmitter "isSelectedAllEvent" |
||||
* @param event case "Tout Sélectionner" cochée ou décochée |
||||
*/ |
||||
selectedAllChecked(event) { |
||||
this.isSelectedAllEvent.emit(event);
|
||||
this.checkedAll = event; |
||||
this.elementsSelected = []; |
||||
|
||||
if(event) |
||||
this.dataSource.map(data => this.elementsSelected.push(data));
|
||||
} |
||||
|
||||
/** |
||||
* Met à jour la liste des éléments sélectionnés et met à jour l'EventEmitter "isSelectedEvent" |
||||
* @param isChecked case cochée ou décochée par l'utilisateur |
||||
* @param data Valeur de la case cochée ou décochée |
||||
*/ |
||||
selectedChecked = (isChecked: boolean, data: T) => { |
||||
this.isSelectedEvent.emit({isSelected: isChecked, selectedElement: data}); |
||||
|
||||
if(isChecked) { |
||||
var index = this.elementsSelected.findIndex(element => element == data);
|
||||
|
||||
if (index === -1)
|
||||
this.elementsSelected.push(data); |
||||
}
|
||||
else { |
||||
this.elementsSelected = this.elementsSelected.filter(element => element != data); |
||||
} |
||||
|
||||
// coche la case "Tout sélectionner" si tous les éléments sont cochés
|
||||
this.elementsSelected.length == this.dataSource.length ? this.checkedAll = true: this.checkedAll = false; |
||||
} |
||||
|
||||
/** |
||||
* Une fois la page fermée, il est nécessaire de se désabonner des Oberservable afin d'éviter les fuites mémoires. |
||||
*/ |
||||
ngOnDestroy() { |
||||
} |
||||
} |
||||
|
@ -0,0 +1,11 @@ |
||||
export interface SelectedElement<T> {
|
||||
/** |
||||
* Détermine si l'élément est sélectionné ou non |
||||
*/ |
||||
isSelected: boolean; |
||||
|
||||
/** |
||||
* Element sélectionné |
||||
*/ |
||||
selectedElement: T; |
||||
} |
Loading…
Reference in new issue