uoa-repository-manager-service/app/features/administration/forms/template-form/template-form.component.ts

370 lines
15 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { DocumentClassification } from './../../../../shared/models/document-classification.interface';
import { Category } from './../../../../shared/models/category.interface';
import { DocumentSubclassificationsService } from './../../../../shared/services/administration/document-subclassifications.service';
import { DocumentSubclassification } from './../../../../shared/models/document-subclassification.interface';
import { IPowerClient } from './../../../../shared/models/ipower-client.interface';
import { Template } from './../../../../shared/models/template.interface';
import { Component, Input, OnInit } from '@angular/core';
import { FormBuilder, Validators } from '@angular/forms';
import { CategoriesService } from 'src/app/shared/services/administration/categories.service';
import { DocumentClassificationsService } from 'src/app/shared/services/administration/document-classifications.service';
import { IpowerClientsService } from 'src/app/shared/services/administration/ipower-clients.service';
import { ErrorHandlingService } from 'src/app/shared/services/error-handling/error-handling.service';
@Component({
selector: 'app-template-form',
templateUrl: './template-form.component.html',
styleUrls: ['./template-form.component.scss']
})
export class TemplateFormComponent implements OnInit {
/*
* Inputs
*/
@Input() dialogLayout: boolean = false; // Controls .scss classes to allow for better dispay in a dialog.
@Input() requiredFields: string[] | boolean = false; // True/False indicates that all/none are required. String[] specifies the form controls required.
@Input() displayValidationMessagesEvenIfPristine: boolean = false; // Serves for manually treating the controls as dirty.
@Input() excludedFormControls: string[]; // Specifies the form controls to be removed and NOT displayed.
/*
* Reactive Form
*/
templateForm = this.fb.group({
documentClassification: [null],
categoryName: [null],
categoryCode: [null],
iPowerClientName: [null],
iPowerClientCode: [null],
documentSubclassification: [null],
abbyyTemplateCode: [null]
});
initiallySetFormValue: Template;
/*
* Other Variables
*/
documentClassificationsList: DocumentClassification[];
categoryNameSuggestions: string[];
categoryCodeSuggestions: string[];
categorySuggestions: Category[];
selectedCategory: Category;
iPowerClientNameSuggestions: string[];
iPowerClientCodeSuggestions: string[];
iPowerClientSuggestions: IPowerClient[];
selectedIPowerClient: IPowerClient;
documentSubclassificationsList: DocumentSubclassification[];
availableDocumentSubclassifications: DocumentSubclassification[];
subCategoryCodeDisabled: boolean = true;
/*
* Constructor & Initialisers
*/
constructor(
private fb: FormBuilder,
private documentClassificationsService: DocumentClassificationsService,
private categoriesService: CategoriesService,
private iPowerClientsService: IpowerClientsService,
private documentSubclassificationsService: DocumentSubclassificationsService,
private errorHandlingService: ErrorHandlingService
) { }
ngOnInit(): void {
this.initData();
this.initValidators()
this.excludeFields();
}
initData() {
this.documentClassificationsService.getAll().subscribe(
value => this.documentClassificationsList = value,
err => this.errorHandlingService.showHttpResponseError(err)
);
// This is NOT the list of Subclassifications used for the dropdown.
this.documentSubclassificationsService.getAll().subscribe(
value => this.documentSubclassificationsList = value,
err => this.errorHandlingService.showHttpResponseError(err)
);
}
// TODO: Have this mechanism offer the use of custom validators too.
initValidators() {
if (!this.requiredFields) { return; }
// In a true/false case.
if (typeof this.requiredFields == 'boolean') {
// If true, enable the required validator for all controls.
if (this.requiredFields) {
Object.keys(this.templateForm.controls).forEach(key => this.templateForm.controls[key].setValidators(Validators.required));
}
// If false, do nothing.
return;
}
// If it was a string array, enable the validators for all provided field-names.
(<string[]>this.requiredFields).forEach(field => this.templateForm.controls[field].setValidators(Validators.required))
}
excludeFields() {
if (!this.excludedFormControls) { return; }
this.excludedFormControls.forEach(field => this.templateForm.removeControl(field));
}
/*
* Auto-suggest & Auto-complete Category
*/
autosuggestCategoryName(event) {
if (!event.query || event.query.length < 3) {
this.categoryNameSuggestions = [];
return;
}
let classId = this.templateForm.get('documentClassification').value ? this.templateForm.get('documentClassification').value.classificationId : null;
this.categoriesService.autosuggestCategoryName(event.query, classId).subscribe(
(values: Category[]) => {
let temp: string[] = [];
this.categorySuggestions = values;
values.map(val => temp.push(val.categoryName));
this.categoryNameSuggestions = temp
},
err => this.errorHandlingService.showHttpResponseError(err)
);
}
autosuggestCategoryCode(event) {
if (event.query.length < 3) {
this.categoryCodeSuggestions = [];
return;
}
let classId = this.templateForm.get('documentClassification').value ? this.templateForm.get('documentClassification').value.classificationId : null;
this.categoriesService.autosuggestCategoryCode(event.query, classId).subscribe(
(values: Category[]) => {
let temp: string[] = [];
this.categorySuggestions = values;
values.map(val => temp.push(val.categoryCode));
this.categoryCodeSuggestions = temp
},
err => this.errorHandlingService.showHttpResponseError(err)
);
}
categoryNameSelected(name: string) {
this.selectedCategory = this.categorySuggestions.find(cat => cat.categoryName == name);
this.templateForm.get('categoryCode')?.patchValue(this.selectedCategory.categoryCode);
this.templateForm.updateValueAndValidity();
}
categoryCodeSelected(code: string) {
this.selectedCategory = this.categorySuggestions.find(cat => cat.categoryCode == code);
this.templateForm.get('categoryName')?.patchValue(this.selectedCategory?.categoryName);
this.templateForm.updateValueAndValidity();
}
/*
* Auto-suggest & Auto-complete IPower Client
*/
autosuggestIPowerClientName(event): void {
if (!event.query || event.query.length < 3) {
this.iPowerClientNameSuggestions = [];
return;
}
this.iPowerClientsService.getClientsByNameOnly(event.query).subscribe(
(values: IPowerClient[]) => {
this.iPowerClientSuggestions = values;
const temp: string[] = [];
values.map(val => temp.push(val.name));
this.iPowerClientNameSuggestions = temp;
},
err => this.errorHandlingService.showHttpResponseError(err)
);
}
autosuggestIPowerClientCode(event): void {
if (event.query.length < 3) {
this.iPowerClientCodeSuggestions = [];
return;
}
this.iPowerClientsService.getClientsByCodeOnly(event.query).subscribe(
(values: IPowerClient[]) => {
this.iPowerClientSuggestions = values;
const temp: string[] = [];
values.map(val => temp.push(val.clientCode));
this.iPowerClientCodeSuggestions = temp;
},
err => this.errorHandlingService.showHttpResponseError(err)
);
}
iPowerClientNameSelected(name: string) {
this.selectedIPowerClient = this.iPowerClientSuggestions.find(client => client.name == name);
this.templateForm.get('iPowerClientCode')?.patchValue(this.selectedIPowerClient ? this.selectedIPowerClient.clientCode : '');
this.templateForm.updateValueAndValidity();
}
iPowerClientCodeSelected(code: string) {
this.selectedIPowerClient = this.iPowerClientSuggestions.find(client => client.clientCode == code);
this.templateForm.get('iPowerClientName')?.patchValue(this.selectedIPowerClient ? this.selectedIPowerClient.name : '');
this.templateForm.updateValueAndValidity();
}
/*
* Other Methods
*/
documentClassificationSelected(selection: DocumentClassification) {
this.availableDocumentSubclassifications = this.documentSubclassificationsList.filter(element => element.documentClassification.classificationId == selection.classificationId);
this.templateForm.get('documentSubclassification')?.setValue(this.availableDocumentSubclassifications[0]); //TODO CHECK
this.subCategoryCodeDisabled = false;
}
/*
* Utility Methods
*/
// Auto-suggest inputs - We have to ensure our reactive form holds values that represent the selectedCategory, otherwise truncate it.
syncSelectedCategory() {
// Ιf our form has no value, truncate the selectedCategory either way.
if (!this.templateForm.get('categoryName')?.value && !this.templateForm.get('categoryCode').value) {
this.selectedCategory = null;
return;
}
// If both or either of our form's values match the selectedCategory's and the other one doesn't have a value, all is good.
// Just sync the values in case one is missing. Otherwise truncate the selectedCategory.
if (
this.templateForm.get('categoryName')?.value == this.selectedCategory.categoryName
|| this.templateForm.get('categoryCode')?.value == this.selectedCategory.categoryCode
) {
this.selectedCategory.categoryName = this.templateForm.get('categoryName')?.value;
this.selectedCategory.categoryCode = this.templateForm.get('categoryCode')?.value;
}
// If both our values were different from the selectedCategory's, truncate it. This is an extremely abnormal scenario.
else {
console.error('WARNING - syncSelectedCategory()', 'Both of our form\'s values were different from the selectedCategory\'s.');
this.selectedCategory = null;
this.templateForm.get('categoryName')?.setValue('');
this.templateForm.get('categoryCode')?.setValue('');
this.templateForm.updateValueAndValidity();
}
}
// Auto-suggest inputs - We have to ensure our reactive form holds values that represent the selectedIPowerClient, otherwise truncate it.
syncSelectedIPowerClient() {
// Ιf our form has no value, truncate the selectedIPowerClient either way.
if (!this.templateForm.get('iPowerClientName')?.value && !this.templateForm.get('iPowerClientCode')?.value) {
this.selectedIPowerClient = null;
return;
}
// If both or either of our form's values match the selectedIPowerClient's and the other one doesn't have a value, all is good.
// Just sync the values in case one is missing. Otherwise truncate the selectedIPowerClient.
if (
this.templateForm.get('iPowerClientName')?.value == this.selectedIPowerClient.name
|| this.templateForm.get('iPowerClientCode')?.value == this.selectedIPowerClient.clientCode
) {
this.selectedIPowerClient.name = this.templateForm.get('iPowerClientName')?.value;
this.selectedIPowerClient.clientCode = this.templateForm.get('iPowerClientCode')?.value;
}
// If both our values were different from the selectedIPowerClient's, truncate it. This is an extremely abnormal scenario.
else {
console.error('WARNING - syncSelectedIPowerClient()', 'Both of our form\'s values were different from the selectedIPowerClient\'s.');
this.selectedIPowerClient = null;
this.templateForm.get('iPowerClientName')?.setValue('');
this.templateForm.get('iPowerClientCode')?.setValue('');
this.templateForm.updateValueAndValidity();
}
}
/*
* API methods
*/
public resetForm(): void {
this.templateForm.reset();
this.selectedCategory = null;
this.selectedIPowerClient = null;
}
public formValue(): Template {
// A field ('documentSubclassification') may be excluded, so we have to check for that too.
let subCatCode = this.templateForm.get('documentSubclassification') ? this.templateForm.get('documentSubclassification').value : null;
let abbyy = this.templateForm.get('abbyyTemplateCode') ? this.templateForm.get('abbyyTemplateCode').value : null;
let docClass = this.templateForm.get('documentClassification') ? this.templateForm.get('documentClassification').value : null;
// We keep track of those two using object-variables separate from our ReactiveForm.
// Thus, we now have to make sure the ReactiveForm really has values that match those objects, before we forward them.
// Also, keep in mind that our auto-suggest inputs limit the user in choosing one of their values.
this.syncSelectedCategory();
this.syncSelectedIPowerClient();
let formValue: Template = {
id: this.initiallySetFormValue ? this.initiallySetFormValue.id : null,
category: this.selectedCategory,
subCategoryCode: subCatCode ? subCatCode.subclassificationName : '',
abbyyTemplate: abbyy,
client: this.selectedIPowerClient,
documentClassification: docClass
};
return formValue;
}
public setValue(value: Template): void {
if (!value) {
return;
}
this.initiallySetFormValue = value;
// If a documentClassification is already selected, enable the subclassification dropdown.
this.subCategoryCodeDisabled = !value.documentClassification;
this.templateForm.get('documentClassification')?.setValue(value.documentClassification);
// Having set the documentClassification -and provided there was one- we must also set the availableDocumentSubclassifications.
this.availableDocumentSubclassifications = this.documentSubclassificationsList.filter(element =>
element.documentClassification.classificationId == value.documentClassification.classificationId
);
this.selectedCategory = value.category;
this.templateForm.get('categoryName')?.setValue(value.category.categoryName);
this.templateForm.get('categoryCode')?.setValue(value.category.categoryCode);
this.selectedIPowerClient = value.client;
this.templateForm.get('iPowerClientName')?.setValue(value.client.name);
this.templateForm.get('iPowerClientCode')?.setValue(value.client.clientCode);
this.templateForm.get('abbyyTemplateCode')?.setValue(value.abbyyTemplate);
// To set the subcategory/subclassification we also have to make sure the documentClassification is the same.
// WARNING: Since we have enabled the [forceSelection] option of the <p-autoComplete>,
// if the availableDocumentSubclassifications are not set, documentSubclassification won't be displayed.
this.templateForm.get('documentSubclassification').setValue(
this.documentSubclassificationsList.find(subClass => (
subClass.subclassificationName == value.subCategoryCode && subClass.documentClassification.classificationId == value.documentClassification.classificationId
))
);
this.templateForm.updateValueAndValidity();
}
public isValid(): boolean {
return this.templateForm.valid;
}
}