Working mix editor
This commit is contained in:
parent
c3122c2e3e
commit
971e3dcb3c
|
@ -13,7 +13,7 @@ services:
|
|||
image: registry.fyloz.dev:5443/colorrecipesexplorer/backend:latest
|
||||
environment:
|
||||
spring_profiles_active: "mysql,debug"
|
||||
cre_database_url: "mysql://database:3307/cre"
|
||||
cre_database_url: "mysql://database/cre"
|
||||
cre_database_username: "root"
|
||||
cre_database_password: "pass"
|
||||
CRE_ENABLE_DB_UPDATE: 1
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<mat-form-field [class.short]="short">
|
||||
<mat-label *ngIf="showLabel">Unités</mat-label>
|
||||
<mat-select [value]="unit" (selectionChange)="unitChange.emit($event.value)">
|
||||
<mat-select [value]="unit" (selectionChange)="onUnitChange($event.value)">
|
||||
<ng-container *ngIf="!short">
|
||||
<mat-option [value]="unitConstants.UNIT_MILLILITER">Millilitres</mat-option>
|
||||
<mat-option [value]="unitConstants.UNIT_LITER">Litres</mat-option>
|
||||
|
|
|
@ -1,17 +1,28 @@
|
|||
import {Component, EventEmitter, Input, Output} from '@angular/core';
|
||||
import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core'
|
||||
import {UNIT_GALLON, UNIT_LITER, UNIT_MILLILITER} from "../../../shared/units";
|
||||
import {FormControl} from '@angular/forms'
|
||||
|
||||
@Component({
|
||||
selector: 'cre-unit-selector',
|
||||
templateUrl: './unit-selector.component.html',
|
||||
styleUrls: ['./unit-selector.component.sass']
|
||||
})
|
||||
export class UnitSelectorComponent {
|
||||
export class UnitSelectorComponent implements OnInit {
|
||||
readonly unitConstants = {UNIT_MILLILITER, UNIT_LITER, UNIT_GALLON}
|
||||
|
||||
@Input() unit = UNIT_MILLILITER
|
||||
@Input() showLabel = true
|
||||
@Input() short = false
|
||||
@Input() control: FormControl | null
|
||||
|
||||
@Output() unitChange = new EventEmitter<string>()
|
||||
|
||||
ngOnInit() {
|
||||
this.control?.setValue(this.unit)
|
||||
}
|
||||
|
||||
onUnitChange(newUnit: string) {
|
||||
this.control?.setValue(newUnit)
|
||||
this.unitChange.emit(newUnit)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,17 @@
|
|||
<cre-mix-form
|
||||
*ngIf="recipe"
|
||||
[recipe]="recipe"
|
||||
[materialTypes]="materialTypes$"
|
||||
[materials]="materials$">
|
||||
</cre-mix-form>
|
||||
<ng-container *ngIf="recipe">
|
||||
<cre-action-bar>
|
||||
<cre-action-group>
|
||||
<cre-primary-button>Retour</cre-primary-button>
|
||||
</cre-action-group>
|
||||
<cre-action-group>
|
||||
<cre-submit-button [valid]="form.valid">Enregistrer</cre-submit-button>
|
||||
</cre-action-group>
|
||||
</cre-action-bar>
|
||||
|
||||
<cre-mix-form
|
||||
#form
|
||||
[recipe]="recipe"
|
||||
[materialTypes]="materialTypes$"
|
||||
[materials]="materials$">
|
||||
</cre-mix-form>
|
||||
</ng-container>
|
||||
|
|
|
@ -1,44 +1,70 @@
|
|||
<cre-table class="mx-auto mt-5" [dataSource]="mixMaterials" [columns]="columns">
|
||||
<ng-container matColumnDef="position">
|
||||
<th mat-header-cell *matHeaderCellDef>Position</th>
|
||||
<td mat-cell *matCellDef="let mixMaterial">{{mixMaterial.position + 1}}</td>
|
||||
</ng-container>
|
||||
<div class="mt-5">
|
||||
<cre-warning-alert *ngIf="materialCount <= 0">
|
||||
<p>Il n'y a actuellement aucun produit enregistré dans le système.</p>
|
||||
<p *ngIf="hasMaterialEditPermission">Vous pouvez en créer un <b><a routerLink="/catalog/material/add">ici</a></b>.
|
||||
</p>
|
||||
</cre-warning-alert>
|
||||
|
||||
<ng-container matColumnDef="positionButtons">
|
||||
<th mat-header-cell *matHeaderCellDef></th>
|
||||
<td mat-cell *matCellDef="let mixMaterial">
|
||||
<cre-table-position-buttons
|
||||
[position]="mixMaterial.position"
|
||||
[min]="0"
|
||||
[max]="mixMaterials.length - 1"
|
||||
(positionChange)="updatePosition(mixMaterial, $event)">
|
||||
</cre-table-position-buttons>
|
||||
</td>
|
||||
</ng-container>
|
||||
<cre-table [hidden]="materialCount <= 0" class="mx-auto" [dataSource]="mixMaterials" [columns]="columns">
|
||||
<ng-container matColumnDef="position">
|
||||
<th mat-header-cell *matHeaderCellDef>Position</th>
|
||||
<td mat-cell *matCellDef="let mixMaterial">{{mixMaterial.position + 1}}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="material">
|
||||
<th mat-header-cell *matHeaderCellDef>Produit</th>
|
||||
<td mat-cell *matCellDef="let mixMaterial">
|
||||
<cre-combo-box
|
||||
[control]="getControls(mixMaterial.position).materialId"
|
||||
[entries]="getAvailableMaterialEntries(mixMaterial.position)">
|
||||
</cre-combo-box>
|
||||
</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="positionButtons">
|
||||
<th mat-header-cell *matHeaderCellDef></th>
|
||||
<td mat-cell *matCellDef="let mixMaterial">
|
||||
<cre-table-position-buttons
|
||||
[position]="mixMaterial.position"
|
||||
[min]="0"
|
||||
[max]="mixMaterials.length - 1"
|
||||
(positionChange)="updatePosition(mixMaterial, $event)">
|
||||
</cre-table-position-buttons>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="quantity">
|
||||
<th mat-header-cell *matHeaderCellDef>Quantité</th>
|
||||
<td mat-cell *matCellDef="let mixMaterial">
|
||||
<cre-input [control]="getControls(mixMaterial.position).quantity" type="number"></cre-input>
|
||||
</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="material">
|
||||
<th mat-header-cell *matHeaderCellDef>Produit</th>
|
||||
<td mat-cell *matCellDef="let mixMaterial">
|
||||
<cre-combo-box
|
||||
[control]="getControls(mixMaterial.position).materialId"
|
||||
[entries]="getAvailableMaterialEntries(mixMaterial.position)">
|
||||
</cre-combo-box>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="endButton">
|
||||
<th mat-header-cell *matHeaderCellDef>
|
||||
<cre-accent-button (click)="addRow()" [disabled]="materialCount - mixMaterials.length <= 0">Ajouter</cre-accent-button>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let mixMaterial">
|
||||
<cre-warn-button (click)="removeRow(mixMaterial)" [disabled]="mixMaterials.length === 1">Retirer</cre-warn-button>
|
||||
</td>
|
||||
</ng-container>
|
||||
</cre-table>
|
||||
<ng-container matColumnDef="quantity">
|
||||
<th mat-header-cell *matHeaderCellDef>Quantité</th>
|
||||
<td mat-cell *matCellDef="let mixMaterial">
|
||||
<cre-input [control]="getControls(mixMaterial.position).quantity" type="number"></cre-input>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="units">
|
||||
<th mat-header-cell *matHeaderCellDef>Unités</th>
|
||||
<td mat-cell *matCellDef="let mixMaterial">
|
||||
<cre-unit-selector
|
||||
*ngIf="!areUnitsPercents(mixMaterial)"
|
||||
[showLabel]="false"
|
||||
[short]="true"
|
||||
[control]="getControls(mixMaterial.position).units">
|
||||
</cre-unit-selector>
|
||||
|
||||
<ng-container *ngIf="areUnitsPercents(mixMaterial)">
|
||||
%
|
||||
</ng-container>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="endButton">
|
||||
<th mat-header-cell *matHeaderCellDef>
|
||||
<cre-accent-button (click)="addRow()" [disabled]="materialCount - mixMaterials.length <= 0">Ajouter
|
||||
</cre-accent-button>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let mixMaterial">
|
||||
<cre-warn-button (click)="removeRow(mixMaterial)" [disabled]="mixMaterials.length === 1">Retirer
|
||||
</cre-warn-button>
|
||||
</td>
|
||||
</ng-container>
|
||||
</cre-table>
|
||||
</div>
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
import {AfterViewInit, ChangeDetectorRef, Component, Input, OnDestroy, ViewChild} from "@angular/core";
|
||||
import {CreTable} from "../../shared/components/tables/tables";
|
||||
import {MixMaterialDto, sortMixMaterialsDto} from "../../shared/model/recipe.model";
|
||||
import {Observable, Subject} from "rxjs";
|
||||
import {Material} from "../../shared/model/material.model";
|
||||
import {FormControl, Validators} from "@angular/forms";
|
||||
import {takeUntil} from "rxjs/operators";
|
||||
import {CreInputEntry} from "../../shared/components/inputs/inputs";
|
||||
import {AfterViewInit, ChangeDetectorRef, Component, Input, OnDestroy, ViewChild, ViewChildren} from '@angular/core'
|
||||
import {CreTable} from '../../shared/components/tables/tables'
|
||||
import {MixMaterialDto, sortMixMaterialsDto} from '../../shared/model/recipe.model'
|
||||
import {Observable, Subject} from 'rxjs'
|
||||
import {Material, materialComparator} from '../../shared/model/material.model'
|
||||
import {FormControl, Validators} from '@angular/forms'
|
||||
import {takeUntil} from 'rxjs/operators'
|
||||
import {CreComboBoxComponent, CreInputEntry} from '../../shared/components/inputs/inputs'
|
||||
import {AccountService} from '../../accounts/services/account.service'
|
||||
import {Permission} from '../../shared/model/user'
|
||||
|
||||
@Component({
|
||||
selector: 'cre-mix-materials-form',
|
||||
|
@ -13,11 +15,12 @@ import {CreInputEntry} from "../../shared/components/inputs/inputs";
|
|||
})
|
||||
export class MixMaterialsForm implements AfterViewInit, OnDestroy {
|
||||
@ViewChild(CreTable) table: CreTable<MixMaterialDto>
|
||||
@ViewChildren(CreComboBoxComponent) materialComboBoxes: CreComboBoxComponent[]
|
||||
|
||||
@Input() materials: Observable<Material[]>
|
||||
@Input() mixMaterials: MixMaterialDto[] = []
|
||||
|
||||
mixMaterials: MixMaterialDto[] = []
|
||||
columns = ['position', 'positionButtons', 'material', 'quantity', 'endButton']
|
||||
columns = ['position', 'positionButtons', 'material', 'quantity', 'units', 'endButton']
|
||||
|
||||
private _allMaterials: Material[]
|
||||
private _controls: ControlsByPosition[] = []
|
||||
|
@ -25,6 +28,7 @@ export class MixMaterialsForm implements AfterViewInit, OnDestroy {
|
|||
private _destroy$ = new Subject<boolean>()
|
||||
|
||||
constructor(
|
||||
private accountService: AccountService,
|
||||
private cdRef: ChangeDetectorRef
|
||||
) {
|
||||
}
|
||||
|
@ -46,18 +50,21 @@ export class MixMaterialsForm implements AfterViewInit, OnDestroy {
|
|||
}
|
||||
|
||||
addRow() {
|
||||
const position = this.nextPosition;
|
||||
const mixMaterial = new MixMaterialDto(0, 0, false, position);
|
||||
const position = this.nextPosition
|
||||
const mixMaterial = new MixMaterialDto(null, 0, false, position)
|
||||
|
||||
const materialIdControl = new FormControl(null, Validators.required)
|
||||
const quantityControl = new FormControl(null, Validators.required)
|
||||
const quantityControl = new FormControl(0, Validators.required)
|
||||
const unitsControl = new FormControl(null, Validators.required)
|
||||
|
||||
materialIdControl.valueChanges
|
||||
.pipe(takeUntil(this._destroy$))
|
||||
.subscribe({
|
||||
next: materialId => {
|
||||
this.mixMaterials.filter(x => x.materialId === mixMaterial.materialId)[0].materialId = materialId
|
||||
mixMaterial.materialId = materialId
|
||||
this.refreshAvailableMaterials()
|
||||
this.cdRef.detectChanges()
|
||||
this.materialComboBoxes.forEach(comboBox => comboBox.reloadEntries())
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -65,7 +72,8 @@ export class MixMaterialsForm implements AfterViewInit, OnDestroy {
|
|||
position,
|
||||
controls: {
|
||||
materialId: materialIdControl,
|
||||
quantity: quantityControl
|
||||
quantity: quantityControl,
|
||||
units: unitsControl
|
||||
}
|
||||
})
|
||||
this._availableMaterialsEntries.push({
|
||||
|
@ -86,15 +94,18 @@ export class MixMaterialsForm implements AfterViewInit, OnDestroy {
|
|||
|
||||
updatePosition(mixMaterial: MixMaterialDto, newPosition: number, switchPositions = true) {
|
||||
const currentPosition = mixMaterial.position
|
||||
const currentControls = this.getControlsByPosition(currentPosition)
|
||||
const currentMaterialEntries = this.getMaterialEntriesByPosition(currentPosition)
|
||||
|
||||
this.getControlsByPosition(currentPosition).position = newPosition
|
||||
this.getMaterialEntriesByPosition(currentPosition).position = newPosition
|
||||
|
||||
// Update before current to prevent position conflicts
|
||||
if (switchPositions) {
|
||||
this.updatePosition(this.getMixMaterialByPosition(newPosition), currentPosition, false)
|
||||
}
|
||||
|
||||
mixMaterial.position = newPosition
|
||||
currentControls.position = newPosition
|
||||
currentMaterialEntries.position = newPosition
|
||||
|
||||
this.sortTable()
|
||||
}
|
||||
|
||||
|
@ -106,8 +117,24 @@ export class MixMaterialsForm implements AfterViewInit, OnDestroy {
|
|||
return this.getMaterialEntriesByPosition(position).entries
|
||||
}
|
||||
|
||||
areUnitsPercents(mixMaterial: MixMaterialDto): boolean {
|
||||
return mixMaterial.materialId ? this._allMaterials.filter(x => x.id === mixMaterial.materialId)[0].materialType.usePercentages : false
|
||||
}
|
||||
|
||||
get hasMaterialEditPermission(): boolean {
|
||||
return this.accountService.hasPermission(Permission.EDIT_MATERIALS)
|
||||
}
|
||||
|
||||
get materialCount(): number {
|
||||
return this._allMaterials ? this._allMaterials.length : 0;
|
||||
return this._allMaterials ? this._allMaterials.length : 0
|
||||
}
|
||||
|
||||
get valid(): boolean {
|
||||
return this._controls
|
||||
.map(controls => controls.controls)
|
||||
.map(controls => [controls.materialId, controls.quantity])
|
||||
.flatMap(controls => controls)
|
||||
.every(control => control.valid)
|
||||
}
|
||||
|
||||
private get nextPosition(): number {
|
||||
|
@ -141,14 +168,27 @@ export class MixMaterialsForm implements AfterViewInit, OnDestroy {
|
|||
|
||||
private filterMaterials(mixMaterial: MixMaterialDto): CreInputEntry[] {
|
||||
return this._allMaterials
|
||||
.filter(material => mixMaterial.materialId === material.id || this.mixMaterials.filter(mm => mm.materialId === material.id).length === 0)
|
||||
.map(material => new CreInputEntry(material.id, material.name))
|
||||
.filter(material => {
|
||||
// Prevent use of percents in first position
|
||||
if (material.materialType.usePercentages && mixMaterial.position === 0) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (mixMaterial.materialId === material.id) {
|
||||
return true
|
||||
}
|
||||
|
||||
return this.mixMaterials.filter(x => x.materialId === material.id).length <= 0
|
||||
})
|
||||
.sort(materialComparator)
|
||||
.map(material => new CreInputEntry(material.id, material.name, material.materialType.prefix ? `[${material.materialType.prefix}] ${material.name}` : material.name))
|
||||
}
|
||||
}
|
||||
|
||||
interface MixMaterialControls {
|
||||
materialId: FormControl
|
||||
quantity: FormControl
|
||||
units: FormControl
|
||||
}
|
||||
|
||||
interface ControlsByPosition {
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
import {AfterViewInit, ChangeDetectorRef, Component, Input, OnDestroy, OnInit, ViewChild} from "@angular/core";
|
||||
import {SubscribingComponent} from "../../shared/components/subscribing.component";
|
||||
import {MixMaterialDto, Recipe, sortMixMaterialsDto} from "../../shared/model/recipe.model";
|
||||
import {ErrorService} from "../../shared/service/error.service";
|
||||
import {ActivatedRoute, Router} from "@angular/router";
|
||||
import {RecipeService} from "../services/recipe.service";
|
||||
import {FormControl, Validators} from "@angular/forms";
|
||||
import {Observable, Subject} from "rxjs";
|
||||
import {MaterialType} from "../../shared/model/materialtype.model";
|
||||
import {MaterialTypeService} from "../../material-type/service/material-type.service";
|
||||
import {CreInputEntry} from "../../shared/components/inputs/inputs";
|
||||
import {filter, map, takeUntil, tap} from "rxjs/operators";
|
||||
import {Material} from "../../shared/model/material.model";
|
||||
import {MaterialService} from "../../material/service/material.service";
|
||||
import {CreTable} from "../../shared/components/tables/tables";
|
||||
import {MatTable} from "@angular/material/table";
|
||||
import {Component, Input, OnInit, ViewChild} from '@angular/core'
|
||||
import {SubscribingComponent} from '../../shared/components/subscribing.component'
|
||||
import {Recipe} from '../../shared/model/recipe.model'
|
||||
import {ErrorService} from '../../shared/service/error.service'
|
||||
import {ActivatedRoute, Router} from '@angular/router'
|
||||
import {RecipeService} from '../services/recipe.service'
|
||||
import {FormControl, Validators} from '@angular/forms'
|
||||
import {Observable} from 'rxjs'
|
||||
import {MaterialType} from '../../shared/model/materialtype.model'
|
||||
import {MaterialTypeService} from '../../material-type/service/material-type.service'
|
||||
import {CreInputEntry} from '../../shared/components/inputs/inputs'
|
||||
import {map} from 'rxjs/operators'
|
||||
import {Material} from '../../shared/model/material.model'
|
||||
import {MaterialService} from '../../material/service/material.service'
|
||||
import {CreForm} from '../../shared/components/forms/forms'
|
||||
import {MixMaterialsForm} from './materials-form'
|
||||
|
||||
@Component({
|
||||
selector: 'cre-mix-add',
|
||||
|
@ -50,30 +50,22 @@ export class MixAdd extends SubscribingComponent {
|
|||
}
|
||||
|
||||
set recipe(recipe: Recipe) {
|
||||
this._recipe = recipe;
|
||||
this._recipe = recipe
|
||||
this.materials$ = this.materialService.getAllForMixCreation(recipe.id)
|
||||
}
|
||||
|
||||
get recipe(): Recipe {
|
||||
return this._recipe;
|
||||
return this._recipe
|
||||
}
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'cre-mix-form',
|
||||
templateUrl: 'form.html'
|
||||
})
|
||||
export class MixForm {
|
||||
@Input() recipe: Recipe
|
||||
@Input() materialTypes: Observable<MaterialType[]>
|
||||
@Input() materials: Observable<Material[]>
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'cre-mix-info-form',
|
||||
templateUrl: 'info-form.html'
|
||||
})
|
||||
export class MixInfoForm implements OnInit {
|
||||
@ViewChild(CreForm) form: CreForm
|
||||
|
||||
@Input() recipe: Recipe
|
||||
@Input() materialTypes: Observable<MaterialType[]>
|
||||
|
||||
|
@ -100,6 +92,25 @@ export class MixInfoForm implements OnInit {
|
|||
get mixMaterialTypeId(): number {
|
||||
return this.controls.materialType.value
|
||||
}
|
||||
|
||||
get valid(): boolean {
|
||||
return this.form.valid
|
||||
}
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'cre-mix-form',
|
||||
templateUrl: 'form.html'
|
||||
})
|
||||
export class MixForm {
|
||||
@ViewChild(MixInfoForm) infoForm: MixInfoForm
|
||||
@ViewChild(MixMaterialsForm) mixMaterialsForm: MixMaterialsForm
|
||||
|
||||
@Input() recipe: Recipe
|
||||
@Input() materialTypes: Observable<MaterialType[]>
|
||||
@Input() materials: Observable<Material[]>
|
||||
|
||||
get valid(): boolean {
|
||||
return this.infoForm?.valid && this.mixMaterialsForm?.valid
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,10 +25,10 @@ import {CreForm, ICreForm} from '../shared/components/forms/forms';
|
|||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class RecipeForm extends SubscribingComponent {
|
||||
@Input() recipe: Recipe | null
|
||||
|
||||
@ViewChild(CreForm) creForm: ICreForm
|
||||
|
||||
@Input() recipe: Recipe | null
|
||||
|
||||
@Output() submitForm = new EventEmitter<Recipe>();
|
||||
|
||||
controls: any
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<mat-form-field>
|
||||
<mat-form-field *ngIf="internalControl">
|
||||
<mat-label>{{label}}</mat-label>
|
||||
<input
|
||||
matInput
|
||||
|
@ -16,8 +16,8 @@
|
|||
</mat-error>
|
||||
|
||||
<mat-autocomplete #auto="matAutocomplete">
|
||||
<mat-option *ngFor="let entry of getEntries()" [value]="entry.value">
|
||||
{{entry.value}}
|
||||
<mat-option *ngFor="let entry of filteredEntries" [value]="entry.value">
|
||||
{{entry.display ? entry.display : entry.value}}
|
||||
</mat-option>
|
||||
</mat-autocomplete>
|
||||
</mat-form-field>
|
||||
|
|
|
@ -16,7 +16,7 @@ import {
|
|||
import {AbstractControl, FormControl, ValidationErrors, ValidatorFn, Validators} from '@angular/forms'
|
||||
import {COMMA, ENTER} from '@angular/cdk/keycodes'
|
||||
import {isObservable, Observable, Subject} from 'rxjs'
|
||||
import {map, takeUntil} from 'rxjs/operators'
|
||||
import {map, startWith, takeUntil} from 'rxjs/operators'
|
||||
import {MatChipInputEvent} from '@angular/material/chips'
|
||||
import {MatAutocomplete, MatAutocompleteSelectedEvent} from '@angular/material/autocomplete'
|
||||
|
||||
|
@ -55,7 +55,7 @@ export class CreInputComponent extends _CreInputBase implements AfterViewInit {
|
|||
constructor(
|
||||
private cdRef: ChangeDetectorRef
|
||||
) {
|
||||
super();
|
||||
super()
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
|
@ -165,34 +165,36 @@ export class CreComboBoxComponent {
|
|||
@ContentChild(TemplateRef) errors: TemplateRef<any>
|
||||
|
||||
internalControl: FormControl
|
||||
filteredEntries: CreInputEntry[]
|
||||
validValue = false
|
||||
|
||||
private _destroy$ = new Subject<boolean>();
|
||||
private _destroy$ = new Subject<boolean>()
|
||||
private _entries: CreInputEntry[]
|
||||
private _controlsInitialized = false
|
||||
|
||||
@Input()
|
||||
set entries(entries: Observable<CreInputEntry[]> | CreInputEntry[]) {
|
||||
if (isObservable(this.entries)) {
|
||||
if (isObservable(entries)) {
|
||||
(entries as Observable<CreInputEntry[]>).pipe(takeUntil(this._destroy$))
|
||||
.subscribe({
|
||||
next: entries => {
|
||||
this._entries = entries
|
||||
this.initControls(entries)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this._entries = (entries as CreInputEntry[])
|
||||
this.initControls((entries as CreInputEntry[]))
|
||||
}
|
||||
|
||||
this.initControls()
|
||||
}
|
||||
|
||||
getEntries(): CreInputEntry[] {
|
||||
return this._entries
|
||||
reloadEntries() {
|
||||
this.filteredEntries = this.filterEntries(this.internalControl.value)
|
||||
}
|
||||
|
||||
private initControls() {
|
||||
if (this._controlsInitialized) return
|
||||
private initControls(entries) {
|
||||
this._entries = entries
|
||||
if (this._controlsInitialized) {
|
||||
return
|
||||
}
|
||||
|
||||
if (this.control.value) {
|
||||
this.internalControl.setValue(this.findEntryByKey(this.control.value)?.value)
|
||||
|
@ -206,7 +208,8 @@ export class CreComboBoxComponent {
|
|||
value: null,
|
||||
disabled: false
|
||||
}, Validators.compose([this.control.validator, this.valueValidator()]))
|
||||
this.internalControl.valueChanges.pipe(takeUntil(this._destroy$))
|
||||
this.internalControl.valueChanges
|
||||
.pipe(takeUntil(this._destroy$))
|
||||
.subscribe({
|
||||
next: value => {
|
||||
if (this.internalControl.valid) {
|
||||
|
@ -214,12 +217,30 @@ export class CreComboBoxComponent {
|
|||
} else {
|
||||
this.control.setValue(null)
|
||||
}
|
||||
|
||||
this.filteredEntries = this.filterEntries(value)
|
||||
}
|
||||
})
|
||||
|
||||
this.reloadEntries()
|
||||
this._controlsInitialized = true
|
||||
}
|
||||
|
||||
private filterEntries(value: string): CreInputEntry[] {
|
||||
if (!value) {
|
||||
return this._entries
|
||||
}
|
||||
|
||||
const valueLowerCase = value.toLowerCase()
|
||||
return this._entries.filter(entry => {
|
||||
if (entry.display) {
|
||||
return entry.display.toLowerCase().includes(valueLowerCase)
|
||||
} else {
|
||||
return entry.value.toLowerCase().includes(valueLowerCase)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private findEntryByKey(key: any): CreInputEntry | null {
|
||||
const found = this._entries.filter(e => e.key === key)
|
||||
if (found.length <= 0) {
|
||||
|
|
Loading…
Reference in New Issue