partial selection model implementation

This commit is contained in:
jonaswinkler
2020-12-27 23:55:19 +01:00
parent 80420a99f5
commit b8e7506de4
7 changed files with 199 additions and 209 deletions

View File

@@ -30,9 +30,15 @@ export class DateDropdownComponent implements OnInit, OnDestroy {
@Input()
dateBefore: string
@Output()
dateBeforeChange = new EventEmitter<string>()
@Input()
dateAfter: string
@Output()
dateAfterChange = new EventEmitter<string>()
@Input()
title: string
@@ -83,6 +89,8 @@ export class DateDropdownComponent implements OnInit, OnDestroy {
}
onChange() {
this.dateAfterChange.emit(this.dateAfter)
this.dateBeforeChange.emit(this.dateBefore)
this.datesSet.emit({after: this.dateAfter, before: this.dateBefore})
}
@@ -91,12 +99,12 @@ export class DateDropdownComponent implements OnInit, OnDestroy {
}
clearBefore() {
this.dateBefore = null;
this.dateBefore = null
this.onChange()
}
clearAfter() {
this.dateAfter = null;
this.dateAfter = null
this.onChange()
}

View File

@@ -1,14 +1,14 @@
<div class="btn-group" ngbDropdown role="group" (openChange)="dropdownOpenChange($event)" #dropdown="ngbDropdown">
<button class="btn btn-sm" id="dropdown{{title}}" ngbDropdownToggle [ngClass]="type !== types.Editing && itemsSelected?.length > 0 ? 'btn-primary' : 'btn-outline-primary'">
<button class="btn btn-sm" id="dropdown{{title}}" ngbDropdownToggle [ngClass]="type !== types.Editing && selectionModel.selectionSize() > 0 ? 'btn-primary' : 'btn-outline-primary'">
<div class="d-none d-md-inline">{{title}}</div>
<div class="d-inline-block d-md-none">
<svg class="toolbaricon" fill="currentColor">
<use attr.xlink:href="assets/bootstrap-icons.svg#{{icon}}" />
</svg>
</div>
<ng-container *ngIf="type !== types.Editing && itemsSelected?.length > 0">
<ng-container *ngIf="type !== types.Editing && selectionModel.selectionSize() > 0">
<div class="badge bg-secondary text-light rounded-pill badge-corner">
{{itemsSelected?.length}}
{{selectionModel.selectionSize()}}
</div>
</ng-container>
</button>
@@ -19,9 +19,9 @@
<input class="form-control" type="text" [(ngModel)]="filterText" placeholder="Filter {{title}}" (keyup.enter)="listFilterEnter()" #listFilterTextInput>
</div>
</div>
<div *ngIf="toggleableItems" class="items">
<ng-container *ngFor="let toggleableItem of toggleableItems | filter: filterText">
<app-toggleable-dropdown-button [toggleableItem]="toggleableItem" (toggle)="toggleItem($event)"></app-toggleable-dropdown-button>
<div *ngIf="selectionModel.items" class="items">
<ng-container *ngFor="let toggleableItem of selectionModel.items | filter: filterText">
<app-toggleable-dropdown-button [toggleableItem]="toggleableItem" (toggle)="selectionModel.toggle(toggleableItem.item)"></app-toggleable-dropdown-button>
</ng-container>
</div>
<button *ngIf="type == types.Editing" class="list-group-item list-group-item-action bg-light" (click)="dropdown.close()" [disabled]="!hasBeenToggled || (toggleableItems | filter: filterText).length == 0">

View File

@@ -3,12 +3,55 @@ import { FilterPipe } from 'src/app/pipes/filter.pipe';
import { NgbDropdown } from '@ng-bootstrap/ng-bootstrap'
import { ToggleableItem, ToggleableItemState } from './toggleable-dropdown-button/toggleable-dropdown-button.component';
import { MatchingModel } from 'src/app/data/matching-model';
import { Subject } from 'rxjs';
export enum FilterableDropdownType {
Filtering = 'filtering',
Editing = 'editing'
}
export class FilterableDropdownSelectionModel {
changed = new Subject<FilterableDropdownSelectionModel>()
multiple = false
items: ToggleableItem[] = []
getSelected() {
return this.items.filter(i => i.state == ToggleableItemState.Selected).map(i => i.item)
}
toggle(item: MatchingModel, fireEvent = true) {
console.log("TOGGLE TAG")
let toggleableItem = this.items.find(i => i.item == item)
console.log(toggleableItem)
if (toggleableItem) {
if (toggleableItem.state == ToggleableItemState.Selected) {
toggleableItem.state = ToggleableItemState.NotSelected
} else {
this.items.forEach(i => {
if (i.item == item) {
i.state = ToggleableItemState.Selected
} else if (!this.multiple) {
i.state = ToggleableItemState.NotSelected
}
})
}
if (fireEvent) {
this.changed.next(this)
}
}
}
selectionSize() {
return this.getSelected().length
}
}
@Component({
selector: 'app-filterable-dropdown',
templateUrl: './filterable-dropdown.component.html',
@@ -24,33 +67,45 @@ export class FilterableDropdownComponent {
@Input()
set items(items: MatchingModel[]) {
if (items) {
this._toggleableItems = items.map(i => {
this._selectionModel.items = items.map(i => {
return {item: i, state: ToggleableItemState.NotSelected, count: i.document_count}
})
}
}
_toggleableItems: ToggleableItem[] = []
@Input()
set toggleableItems (toggleableItems: ToggleableItem[]) {
if (this.type == FilterableDropdownType.Editing && this.dropdown?.isOpen()) return
else this._toggleableItems = toggleableItems
get items(): MatchingModel[] {
return this._selectionModel.items.map(i => i.item)
}
get toggleableItems(): ToggleableItem[] {
return this._toggleableItems
}
_selectionModel = new FilterableDropdownSelectionModel()
@Input()
set itemsSelected(itemsSelected: MatchingModel[]) {
this.toggleableItems.forEach(i => {
i.state = (itemsSelected.find(is => is.id == i.item.id)) ? ToggleableItemState.Selected : ToggleableItemState.NotSelected
set selectionModel(model: FilterableDropdownSelectionModel) {
if (this.selectionModel) {
this.selectionModel.changed.complete()
model.items = this.selectionModel.items
model.multiple = this.selectionModel.multiple
}
model.changed.subscribe(updatedModel => {
this.selectionModelChange.next(updatedModel)
})
this._selectionModel = model
}
get itemsSelected(): MatchingModel[] {
return this.toggleableItems.filter(ti => ti.state == ToggleableItemState.Selected).map(ti => ti.item)
get selectionModel(): FilterableDropdownSelectionModel {
return this._selectionModel
}
@Output()
selectionModelChange = new EventEmitter<FilterableDropdownSelectionModel>()
@Input()
set multiple(value: boolean) {
this.selectionModel.multiple = value
}
get multiple() {
return this.selectionModel.multiple
}
@Input()
@@ -64,50 +119,40 @@ export class FilterableDropdownComponent {
types = FilterableDropdownType
@Input()
singular: boolean = false
@Output()
toggle = new EventEmitter()
@Output()
open = new EventEmitter()
@Output()
editingComplete = new EventEmitter()
hasBeenToggled:boolean = false
constructor(private filterPipe: FilterPipe) { }
constructor(private filterPipe: FilterPipe) {
this.selectionModel = new FilterableDropdownSelectionModel()
}
toggleItem(toggleableItem: ToggleableItem): void {
if (this.singular && toggleableItem.state == ToggleableItemState.Selected) {
this._toggleableItems.filter(ti => ti.item.id !== toggleableItem.item.id).forEach(ti => ti.state = ToggleableItemState.NotSelected)
}
this.hasBeenToggled = true
this.toggle.emit(toggleableItem.item)
// if (this.singular && toggleableItem.state == ToggleableItemState.Selected) {
// this.selectionModel.items.filter(ti => ti.item.id !== toggleableItem.item.id).forEach(ti => ti.state = ToggleableItemState.NotSelected)
// }
// this.hasBeenToggled = true
// this.toggle.emit(toggleableItem.item)
}
dropdownOpenChange(open: boolean): void {
if (open) {
setTimeout(() => {
this.listFilterTextInput.nativeElement.focus();
}, 0)
this.hasBeenToggled = false
this.open.next()
} else {
this.filterText = ''
if (this.type == FilterableDropdownType.Editing) this.editingComplete.emit(this.toggleableItems)
}
// if (open) {
// setTimeout(() => {
// this.listFilterTextInput.nativeElement.focus();
// }, 0)
// this.hasBeenToggled = false
// this.open.next()
// } else {
// this.filterText = ''
// if (this.type == FilterableDropdownType.Editing) this.editingComplete.emit(this.toggleableItems)
// }
}
listFilterEnter(): void {
let filtered = this.filterPipe.transform(this.toggleableItems, this.filterText)
if (filtered.length == 1) {
let toggleableItem = this.toggleableItems.find(ti => ti.item.id == filtered[0].item.id)
if (toggleableItem) toggleableItem.state = ToggleableItemState.Selected
this.toggleItem(filtered[0])
this.dropdown.close()
}
// let filtered = this.filterPipe.transform(this.toggleableItems, this.filterText)
// if (filtered.length == 1) {
// let toggleableItem = this.toggleableItems.find(ti => ti.item.id == filtered[0].item.id)
// if (toggleableItem) toggleableItem.state = ToggleableItemState.Selected
// this.toggleItem(filtered[0])
// this.dropdown.close()
// }
}
}

View File

@@ -31,8 +31,7 @@ export class ToggleableDropdownButtonComponent {
}
toggleItem(): void {
this.toggleableItem.state = (this.toggleableItem.state == ToggleableItemState.NotSelected || this.toggleableItem.state == ToggleableItemState.PartiallySelected) ? ToggleableItemState.Selected : ToggleableItemState.NotSelected
this.toggle.emit(this.toggleableItem)
this.toggle.emit()
}
getSelectedIconName() {