@esfaenza/forms-and-validations 12.2.26 → 12.2.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bundles/esfaenza-forms-and-validations.umd.js +211 -75
- package/bundles/esfaenza-forms-and-validations.umd.js.map +1 -1
- package/esfaenza-forms-and-validations.metadata.json +1 -1
- package/esm2015/lib/forms/base-form-control.js +60 -24
- package/esm2015/lib/forms/form-adaptive/form-adaptive.component.js +78 -20
- package/esm2015/lib/forms/form-autocomplete/form-autocomplete.component.js +69 -17
- package/esm2015/lib/forms/form-multiselect/form-multiselect.component.js +3 -2
- package/esm2015/lib/forms/form-template/form-template.component.js +2 -2
- package/esm2015/lib/validations/validation-autocomplete/validation-autocomplete.component.js +1 -13
- package/fesm2015/esfaenza-forms-and-validations.js +207 -72
- package/fesm2015/esfaenza-forms-and-validations.js.map +1 -1
- package/lib/forms/base-form-control.d.ts +24 -0
- package/lib/forms/form-adaptive/form-adaptive.component.d.ts +22 -0
- package/lib/forms/form-autocomplete/form-autocomplete.component.d.ts +22 -1
- package/lib/forms/form-multiselect/form-multiselect.component.d.ts +1 -0
- package/lib/validations/validation-autocomplete/validation-autocomplete.component.d.ts +0 -4
- package/package.json +12 -12
|
@@ -1179,10 +1179,6 @@ class ValidationAutocompleteComponent extends BaseValidation {
|
|
|
1179
1179
|
* @ignore
|
|
1180
1180
|
*/
|
|
1181
1181
|
this.onTouched = () => { }; //placeholder on touched function
|
|
1182
|
-
//******************** Funzione di throttling per non spammare richieste in caso di animazioni attivate
|
|
1183
|
-
//TODO: spostarla in un metodo di utilità (esfaenza/extensions)
|
|
1184
|
-
/** @ignore */
|
|
1185
|
-
this.executionTimers = {};
|
|
1186
1182
|
}
|
|
1187
1183
|
/**
|
|
1188
1184
|
* @ignore
|
|
@@ -1264,14 +1260,6 @@ class ValidationAutocompleteComponent extends BaseValidation {
|
|
|
1264
1260
|
registerOnTouched(fn) {
|
|
1265
1261
|
this.onTouched = fn;
|
|
1266
1262
|
}
|
|
1267
|
-
/** @ignore */
|
|
1268
|
-
throttla(id, func, throttleTime) {
|
|
1269
|
-
//Se ho la funzione che vuole eseguire ripulisco quel timeout
|
|
1270
|
-
if (this.executionTimers[id])
|
|
1271
|
-
clearTimeout(this.executionTimers[id]);
|
|
1272
|
-
//Ricreo il timeout per eseguire quella funzione dopo throttleTime millisecondi
|
|
1273
|
-
this.executionTimers[id] = setTimeout(() => { func(); this.executionTimers[id] = null; }, throttleTime);
|
|
1274
|
-
}
|
|
1275
1263
|
}
|
|
1276
1264
|
ValidationAutocompleteComponent.decorators = [
|
|
1277
1265
|
{ type: Component, args: [{
|
|
@@ -1428,6 +1416,14 @@ class BaseFormControl {
|
|
|
1428
1416
|
* Evento chiamato alla modifica del valore collegato a questo campo
|
|
1429
1417
|
*/
|
|
1430
1418
|
this.inputChange = new EventEmitter();
|
|
1419
|
+
/**
|
|
1420
|
+
* Cache delle condizioni scritte tipo :prop?(Roba con {prop})
|
|
1421
|
+
*/
|
|
1422
|
+
this.BindCheckingGroups = [];
|
|
1423
|
+
/**
|
|
1424
|
+
* Cache delle proprietà scritte tipo --> {prop}
|
|
1425
|
+
*/
|
|
1426
|
+
this.BindProperties = [];
|
|
1431
1427
|
if (ngControl == null) {
|
|
1432
1428
|
if (!this.handleNullNgControl())
|
|
1433
1429
|
console.error("ngControl nullo per qualche motivo! Il 90% delle funzionalità di questo input saranno disabilitate");
|
|
@@ -1514,35 +1510,63 @@ class BaseFormControl {
|
|
|
1514
1510
|
// Cache locale per evitare di rifare dei regex.match ogni santa volta
|
|
1515
1511
|
if (this.Source.length > 0) {
|
|
1516
1512
|
this.BoundSource = [];
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
iffedMatches.forEach(m => {
|
|
1522
|
-
// Stessa regex di sopra ma il tag "i" serve per tirare fuori i singoli capturing group e per qualche motivo
|
|
1523
|
-
// new RegExp(baseRegex, "g") non funziona quindi non ho potuto razionalizzarlo
|
|
1524
|
-
let groups = m.match(/:([a-z]+)\?\(([^\(\)]+)\)/i);
|
|
1525
|
-
bindCheckingGroups.push({ global: m, prop: groups[1], whenexists: groups[2] });
|
|
1526
|
-
});
|
|
1527
|
-
}
|
|
1528
|
-
// Blocco per tirare fuori le proprietà scritte tipo --> {prop}
|
|
1529
|
-
var bindProperties = [];
|
|
1530
|
-
var matches = this.Display.match(/{[a-z]+}/gi);
|
|
1531
|
-
if (matches)
|
|
1532
|
-
matches.forEach(m => { bindProperties.push({ global: m, prop: m.substring(1, m.length - 1) }); });
|
|
1513
|
+
if (this.BindCheckingGroups.length == 0)
|
|
1514
|
+
this.evaluateBindCheckingGroups();
|
|
1515
|
+
if (this.BindProperties.length == 0)
|
|
1516
|
+
this.evaluateBindProperties();
|
|
1533
1517
|
// Blocco per generare la descrizione finale di un elemento
|
|
1534
1518
|
this.Source.forEach(s => {
|
|
1535
|
-
// Parto sempre dalla variabile di Display, poi sostituisco pezzo per pezzo
|
|
1536
|
-
let desc = this.Display;
|
|
1537
|
-
// Taglio o mantengo le condizioni in base alla proprietà su cui fare check
|
|
1538
|
-
// Dopodiché scrivo tutte le proprietà
|
|
1539
|
-
bindCheckingGroups.forEach(t => { desc = desc.replace(t.global, (s[t.prop] != null && s[t.prop] != undefined) ? t.whenexists : ""); });
|
|
1540
|
-
bindProperties.forEach(t => { desc = desc.replace(t.global, s[t.prop]); });
|
|
1541
1519
|
// Aggiungo alla BoundSource in formato standard KeyValue
|
|
1542
|
-
this.BoundSource.push(
|
|
1520
|
+
this.BoundSource.push(this.transformSourceItem(s));
|
|
1543
1521
|
});
|
|
1544
1522
|
}
|
|
1545
1523
|
}
|
|
1524
|
+
/**
|
|
1525
|
+
* Valuta il contenuto della variabile BindCheckingGroups
|
|
1526
|
+
*/
|
|
1527
|
+
evaluateBindCheckingGroups() {
|
|
1528
|
+
// Blocco per tirare fuori le condizioni scritte tipo --> :prop?(Roba con {prop})
|
|
1529
|
+
var iffedMatches = this.Display.match(/:([a-z]+)\?\(([^\(\)]+)\)/g);
|
|
1530
|
+
if (iffedMatches) {
|
|
1531
|
+
iffedMatches.forEach(m => {
|
|
1532
|
+
// Stessa regex di sopra ma il tag "i" serve per tirare fuori i singoli capturing group e per qualche motivo
|
|
1533
|
+
// new RegExp(baseRegex, "g") non funziona quindi non ho potuto razionalizzarlo
|
|
1534
|
+
let groups = m.match(/:([a-z]+)\?\(([^\(\)]+)\)/i);
|
|
1535
|
+
this.BindCheckingGroups.push({ global: m, prop: groups[1], whenexists: groups[2] });
|
|
1536
|
+
});
|
|
1537
|
+
}
|
|
1538
|
+
}
|
|
1539
|
+
/**
|
|
1540
|
+
* Valuta il contenuto della variabile BindProperties
|
|
1541
|
+
*/
|
|
1542
|
+
evaluateBindProperties() {
|
|
1543
|
+
// Blocco per tirare fuori le proprietà scritte tipo --> {prop}
|
|
1544
|
+
var matches = this.Display.match(/{[a-z]+}/gi);
|
|
1545
|
+
if (matches)
|
|
1546
|
+
matches.forEach(m => { this.BindProperties.push({ global: m, prop: m.substring(1, m.length - 1) }); });
|
|
1547
|
+
}
|
|
1548
|
+
/**
|
|
1549
|
+
* Trasforma un oggetto della Source alla sua versione "nuova" basandosi sulle informazioni su gruppi e proprietà
|
|
1550
|
+
*
|
|
1551
|
+
* @param {any} item Oggetto da trasformare
|
|
1552
|
+
*
|
|
1553
|
+
* @returns {{id: string, description: string}} Oggetto finale trasformato
|
|
1554
|
+
*/
|
|
1555
|
+
transformSourceItem(s) {
|
|
1556
|
+
// Parto sempre dalla variabile di Display, poi sostituisco pezzo per pezzo
|
|
1557
|
+
let desc = this.Display;
|
|
1558
|
+
// Taglio o mantengo le condizioni in base alla proprietà su cui fare check
|
|
1559
|
+
// Dopodiché scrivo tutte le proprietà
|
|
1560
|
+
for (let i = 0; i < this.BindCheckingGroups.length; i++) {
|
|
1561
|
+
let t = this.BindCheckingGroups[i];
|
|
1562
|
+
desc = desc.replace(t.global, (s[t.prop] != null && s[t.prop] != undefined) ? t.whenexists : "");
|
|
1563
|
+
}
|
|
1564
|
+
for (let i = 0; i < this.BindProperties.length; i++) {
|
|
1565
|
+
let t = this.BindProperties[i];
|
|
1566
|
+
desc = desc.replace(t.global, s[t.prop]);
|
|
1567
|
+
}
|
|
1568
|
+
return { id: s[this.IdField], description: desc };
|
|
1569
|
+
}
|
|
1546
1570
|
/**
|
|
1547
1571
|
* Indica se il comopnente in questione è in grado di gestire ngControl nulli.
|
|
1548
1572
|
* Di default è **false**
|
|
@@ -1934,10 +1958,23 @@ class FormAdaptiveComponent extends BaseFormControl {
|
|
|
1934
1958
|
* Numero minimo di caratteri con cui cercare
|
|
1935
1959
|
*/
|
|
1936
1960
|
this.MinChars = 3;
|
|
1961
|
+
/**
|
|
1962
|
+
* Indica se i controlli devono essere effettuati tenendo conto del Case o meno. Vale solo qualora la **Source** fosse fornita
|
|
1963
|
+
*/
|
|
1964
|
+
this.CaseSensitive = false;
|
|
1937
1965
|
/**
|
|
1938
1966
|
* Variabile interna che gestisce se effettuare il riallineamento dei dati o meno
|
|
1939
1967
|
*/
|
|
1940
1968
|
this.alignValues = false;
|
|
1969
|
+
/**
|
|
1970
|
+
* Indica se ignorare il prossimo evento writeValue che normalmente dovrebbe richiedere la nuova source. Serve per quando l'utente seleziona un elemento:
|
|
1971
|
+
* Subito dopo partirebbe un altro evento modelChange che ricaricherebbe nuovamente la source
|
|
1972
|
+
*/
|
|
1973
|
+
this.ignoreNextWriteValue = false;
|
|
1974
|
+
/**
|
|
1975
|
+
* Cache della sorgente originale POST binding, in modo da poter fare filtri in locale qualora la **SearchFunction** non fosse definita e la **Source** fosse assegnata
|
|
1976
|
+
*/
|
|
1977
|
+
this.FilteredBoundSource = [];
|
|
1941
1978
|
//******************** Funzione di throttling per non spammare richieste in caso di animazioni attivate
|
|
1942
1979
|
//TODO: spostarla in un metodo di utilità (esfaenza/extensions)
|
|
1943
1980
|
/** @ignore */
|
|
@@ -1948,11 +1985,19 @@ class FormAdaptiveComponent extends BaseFormControl {
|
|
|
1948
1985
|
* @ignore
|
|
1949
1986
|
*/
|
|
1950
1987
|
ngOnChanges(changes) {
|
|
1988
|
+
var _a;
|
|
1951
1989
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1952
1990
|
const newSource = changes["Source"];
|
|
1953
1991
|
const newType = changes["Type"];
|
|
1954
|
-
if (newSource)
|
|
1992
|
+
if (newSource) {
|
|
1955
1993
|
this.tryBindSourceDisplay();
|
|
1994
|
+
// Prima assegnazione se cambia la source sotto (quindi se viene bindata direttamente da HTML)
|
|
1995
|
+
if (this.Type == "autocomplete" && (((_a = this.Model) === null || _a === void 0 ? void 0 : _a.length) || 0) >= this.MinChars && !this.SearchFunction)
|
|
1996
|
+
this.FilteredBoundSource = this.BoundSource;
|
|
1997
|
+
else
|
|
1998
|
+
this.FilteredBoundSource = [];
|
|
1999
|
+
this.cdr.markForCheck();
|
|
2000
|
+
}
|
|
1956
2001
|
if (newType && this.Model)
|
|
1957
2002
|
this.writeValue(this.Model);
|
|
1958
2003
|
});
|
|
@@ -1978,14 +2023,16 @@ class FormAdaptiveComponent extends BaseFormControl {
|
|
|
1978
2023
|
if (this.Type == "file")
|
|
1979
2024
|
obj = this.ModelFile;
|
|
1980
2025
|
if (this.Type == "autocomplete") {
|
|
1981
|
-
this.SearchFunction
|
|
1982
|
-
this.
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
this.Model = val ? val.description : obj;
|
|
2026
|
+
if (this.SearchFunction) {
|
|
2027
|
+
this.SearchFunction(obj, true).subscribe(t => {
|
|
2028
|
+
this.Source = t;
|
|
2029
|
+
this.tryBindSourceDisplay();
|
|
2030
|
+
setTimeout(() => { this.finalizeValue(obj); });
|
|
1987
2031
|
});
|
|
1988
|
-
|
|
2032
|
+
return;
|
|
2033
|
+
}
|
|
2034
|
+
else
|
|
2035
|
+
this.finalizeValue(obj);
|
|
1989
2036
|
}
|
|
1990
2037
|
super.writeValue(obj);
|
|
1991
2038
|
if (this.alignValues) {
|
|
@@ -1993,24 +2040,56 @@ class FormAdaptiveComponent extends BaseFormControl {
|
|
|
1993
2040
|
this.cdr.markForCheck();
|
|
1994
2041
|
}
|
|
1995
2042
|
}
|
|
2043
|
+
/**
|
|
2044
|
+
* Dato un valore verifica se può restituire le informazioni trovate in **Source** con id uguale a **value** o se deve restituire il valore in se
|
|
2045
|
+
*
|
|
2046
|
+
* @param {any} value Valore scritto nell'input di testo
|
|
2047
|
+
*/
|
|
2048
|
+
finalizeValue(value) {
|
|
2049
|
+
var val = this.Source.find(t => t.id == value);
|
|
2050
|
+
this.propagateChange(val ? val.id : value);
|
|
2051
|
+
this.Model = val ? val.description : value;
|
|
2052
|
+
}
|
|
1996
2053
|
/**
|
|
1997
2054
|
* Evento di filtro della sorgente dati in base all'input utente
|
|
1998
2055
|
*
|
|
1999
2056
|
* @param {string} event Input utente
|
|
2000
2057
|
*/
|
|
2001
2058
|
filterSource(event) {
|
|
2002
|
-
if (
|
|
2003
|
-
this.
|
|
2059
|
+
if (this.ignoreNextWriteValue) {
|
|
2060
|
+
this.ignoreNextWriteValue = false;
|
|
2004
2061
|
return;
|
|
2005
2062
|
}
|
|
2006
|
-
|
|
2063
|
+
// Quando filtro la source, se non devo ignorare l'evento devo comunque assicurarmi di impostare il valore selezionato a null
|
|
2064
|
+
super.changed("");
|
|
2065
|
+
if (!event && this.MinChars == 0 && !this.SearchFunction) {
|
|
2066
|
+
this.FilteredBoundSource = this.BoundSource;
|
|
2067
|
+
return;
|
|
2068
|
+
}
|
|
2069
|
+
if (!event || event.length < this.MinChars) {
|
|
2070
|
+
this.FilteredBoundSource = [];
|
|
2071
|
+
return;
|
|
2072
|
+
}
|
|
2073
|
+
if (!this.SearchFunction && (!this.Source || this.Source.length == 0))
|
|
2007
2074
|
throw "Impossibile filtrare gli elementi senza una funzione di ricerca che restituisca una lista di { id: string, description: string }";
|
|
2008
|
-
this.
|
|
2009
|
-
this.
|
|
2010
|
-
this.
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2075
|
+
if (this.SearchFunction) {
|
|
2076
|
+
this.throttla("filtersource", () => {
|
|
2077
|
+
this.SearchFunction(event, false).subscribe(t => {
|
|
2078
|
+
this.Source = t;
|
|
2079
|
+
this.tryBindSourceDisplay();
|
|
2080
|
+
// In questo caso è già filtrata dalla SearchFunction
|
|
2081
|
+
this.FilteredBoundSource = this.BoundSource;
|
|
2082
|
+
this.cdr.markForCheck();
|
|
2083
|
+
});
|
|
2084
|
+
}, 400);
|
|
2085
|
+
}
|
|
2086
|
+
else {
|
|
2087
|
+
this.throttla("filtersource", () => {
|
|
2088
|
+
// In questo caso devo filtrare io in memoria
|
|
2089
|
+
this.FilteredBoundSource = this.BoundSource.filter(t => (this.CaseSensitive && t.description.includes(event)) || (!this.CaseSensitive && t.description.toLowerCase().includes(event.toLowerCase())));
|
|
2090
|
+
this.cdr.markForCheck();
|
|
2091
|
+
}, 100);
|
|
2092
|
+
}
|
|
2014
2093
|
}
|
|
2015
2094
|
/**
|
|
2016
2095
|
* Metodo richiamato quando viene modificato il modello del campo di input
|
|
@@ -2025,6 +2104,8 @@ class FormAdaptiveComponent extends BaseFormControl {
|
|
|
2025
2104
|
var toEmit = this.dateAdapter.clone(this.Model);
|
|
2026
2105
|
toEmit = toEmit.format("HH:mm:ss");
|
|
2027
2106
|
}
|
|
2107
|
+
if (this.Type == "autocomplete")
|
|
2108
|
+
this.ignoreNextWriteValue = true;
|
|
2028
2109
|
super.changed(toEmit);
|
|
2029
2110
|
}
|
|
2030
2111
|
/**
|
|
@@ -2076,7 +2157,7 @@ FormAdaptiveComponent.decorators = [
|
|
|
2076
2157
|
{ type: Component, args: [{
|
|
2077
2158
|
selector: "form-adaptive",
|
|
2078
2159
|
providers: [{ provide: LocalizationService, useClass: FormAdaptiveComponentLoc }],
|
|
2079
|
-
template: "<ng-container *ngIf=\"!FormLayout\">\r\n <ng-container *ngTemplateOutlet=\"controlTemplate\"></ng-container>\r\n</ng-container>\r\n\r\n<div *ngIf=\"FormLayout\" class=\"form-group row {{FormGroupClass}}\" [class.app-margin-bottom-0]=\"Last\">\r\n <label class=\"col-md-{{LabelColWidth}} m-t-5\">{{Label}}{{Required ? '*' : ''}}:</label>\r\n <div class=\"col-md-{{InputColWidth}}\">\r\n <ng-container *ngTemplateOutlet=\"controlTemplate\"></ng-container>\r\n </div>\r\n <div class=\"clearfix\"></div>\r\n</div>\r\n\r\n<ng-template #controlTemplate>\r\n <div *ngIf=\"!Type\" class=\"app-margin-top-5\">\r\n <em>{{TypeMissingMessage}}</em>\r\n </div>\r\n \r\n <!--Se currency-->\r\n <div *ngIf=\"Type == 'currency'\">\r\n <val-currency [forceInvalid]=\"ForcedError\"\r\n [CurrencyOptions]=\"{ prefix: '', thousands: '.', decimal: ',', precision: Precision, align: Alignment }\" [noValidate]=\"!Validation\"\r\n #validationControl=\"ngModel\" type=\"text\" [readonly]=\"Readonly\" [submitted]=\"Form?.submitted\" [required]=\"Required\" [(ngModel)]=\"Model\" name=\"{{GeneratedName}}\" autocomplete=\"off\" (inputChange)=\"changed();\"></val-currency>\r\n </div>\r\n <!--Se data-->\r\n <div *ngIf=\"Type == 'date'\">\r\n <val-date #validationControl=\"ngModel\" [forceInvalid]=\"ForcedError\" [noValidate]=\"!Validation\" [readonly]=\"Readonly\" [submitted]=\"Form?.submitted\" [required]=\"Required\" [(ngModel)]=\"Model\" name=\"{{GeneratedName}}\" autocomplete=\"off\" (inputChange)=\"changed();\"></val-date>\r\n </div>\r\n <!--Se stringa-->\r\n <div *ngIf=\"Type == 'string'\">\r\n <val-input #validationControl=\"ngModel\" [forceInvalid]=\"ForcedError\" [noValidate]=\"!Validation\" [readonly]=\"Readonly\" [submitted]=\"Form?.submitted\" type=\"text\" pattern=\"{{Pattern || ''}}\" [required]=\"Required\" [(ngModel)]=\"Model\" name=\"{{GeneratedName}}\" autocomplete=\"off\" (inputChange)=\"changed();\"></val-input>\r\n </div>\r\n <!--Se numero-->\r\n <div *ngIf=\"Type == 'float' || Type == 'number'\">\r\n <val-input #validationControl=\"ngModel\" [forceInvalid]=\"ForcedError\" [noValidate]=\"!Validation\" [readonly]=\"Readonly\" [submitted]=\"Form?.submitted\" type=\"text\" pattern=\"{{Pattern || '^([0-9]*[,])?[0-9]+$'}}\" [required]=\"Required\" [(ngModel)]=\"Model\" name=\"{{GeneratedName}}\" autocomplete=\"off\" (inputChange)=\"changed();\"></val-input>\r\n </div>\r\n <!--Se numero intero-->\r\n <div *ngIf=\"Type == 'int'\">\r\n <val-input #validationControl=\"ngModel\" [forceInvalid]=\"ForcedError\" [noValidate]=\"!Validation\" [readonly]=\"Readonly\" [submitted]=\"Form?.submitted\" type=\"text\" pattern=\"{{Pattern || '^[0-9]\\\\d*$'}}\" [required]=\"Required\" [(ngModel)]=\"Model\" name=\"{{GeneratedName}}\" autocomplete=\"off\" (inputChange)=\"changed();\"></val-input>\r\n </div>\r\n <!--Se boolean-->\r\n <div class=\"m-t-5\" *ngIf=\"Type == 'boolean'\">\r\n <input #validationControl=\"ngModel\" [readonly]=\"Readonly\" type=\"checkbox\" class=\"app-pointer\" [(ngModel)]=\"Model\" name=\"{{GeneratedName}}\" (ngModelChange)=\"changed();\" />\r\n </div>\r\n <!--Se enum-->\r\n <div *ngIf=\"Type == 'enum'\">\r\n <val-select #validationControl=\"ngModel\" [forceInvalid]=\"ForcedError\" [noValidate]=\"!Validation\" [readonly]=\"Readonly\" [submitted]=\"Form?.submitted\" [placeHolderValue]=\"''\" [placeholder]=\"Required ? ('Select' | localize : lc) + '...' : Placeholder\" [required]=\"Required\" [(ngModel)]=\"Model\" (inputChange)=\"changed();\" name=\"{{GeneratedName}}\">\r\n <option *ngFor=\"let val of BoundSource\" [value]=\"val.id\">{{val.description}}</option>\r\n </val-select>\r\n </div>\r\n <!--Se autocomplete-->\r\n <div *ngIf=\"Type == 'autocomplete'\">\r\n <val-autocomplete #validationControl=\"ngModel\" [forceInvalid]=\"ForcedError\" [noValidate]=\"!Validation\" [readonly]=\"Readonly\" [submitted]=\"Form?.submitted\" [required]=\"Required\" [placeholder]=\"Required ? ('Select' | localize : lc) + '...' : Placeholder\" [(ngModel)]=\"Model\" name=\"{{GeneratedName}}\" [FilteredSource]=\"
|
|
2160
|
+
template: "<ng-container *ngIf=\"!FormLayout\">\r\n <ng-container *ngTemplateOutlet=\"controlTemplate\"></ng-container>\r\n</ng-container>\r\n\r\n<div *ngIf=\"FormLayout\" class=\"form-group row {{FormGroupClass}}\" [class.app-margin-bottom-0]=\"Last\">\r\n <label class=\"col-md-{{LabelColWidth}} m-t-5\">{{Label}}{{Required ? '*' : ''}}:</label>\r\n <div class=\"col-md-{{InputColWidth}}\">\r\n <ng-container *ngTemplateOutlet=\"controlTemplate\"></ng-container>\r\n </div>\r\n <div class=\"clearfix\"></div>\r\n</div>\r\n\r\n<ng-template #controlTemplate>\r\n <div *ngIf=\"!Type\" class=\"app-margin-top-5\">\r\n <em>{{TypeMissingMessage}}</em>\r\n </div>\r\n \r\n <!--Se currency-->\r\n <div *ngIf=\"Type == 'currency'\">\r\n <val-currency [forceInvalid]=\"ForcedError\"\r\n [CurrencyOptions]=\"{ prefix: '', thousands: '.', decimal: ',', precision: Precision, align: Alignment }\" [noValidate]=\"!Validation\"\r\n #validationControl=\"ngModel\" type=\"text\" [readonly]=\"Readonly\" [submitted]=\"Form?.submitted\" [required]=\"Required\" [(ngModel)]=\"Model\" name=\"{{GeneratedName}}\" autocomplete=\"off\" (inputChange)=\"changed();\"></val-currency>\r\n </div>\r\n <!--Se data-->\r\n <div *ngIf=\"Type == 'date'\">\r\n <val-date #validationControl=\"ngModel\" [forceInvalid]=\"ForcedError\" [noValidate]=\"!Validation\" [readonly]=\"Readonly\" [submitted]=\"Form?.submitted\" [required]=\"Required\" [(ngModel)]=\"Model\" name=\"{{GeneratedName}}\" autocomplete=\"off\" (inputChange)=\"changed();\"></val-date>\r\n </div>\r\n <!--Se stringa-->\r\n <div *ngIf=\"Type == 'string'\">\r\n <val-input #validationControl=\"ngModel\" [forceInvalid]=\"ForcedError\" [noValidate]=\"!Validation\" [readonly]=\"Readonly\" [submitted]=\"Form?.submitted\" type=\"text\" pattern=\"{{Pattern || ''}}\" [required]=\"Required\" [(ngModel)]=\"Model\" name=\"{{GeneratedName}}\" autocomplete=\"off\" (inputChange)=\"changed();\"></val-input>\r\n </div>\r\n <!--Se numero-->\r\n <div *ngIf=\"Type == 'float' || Type == 'number'\">\r\n <val-input #validationControl=\"ngModel\" [forceInvalid]=\"ForcedError\" [noValidate]=\"!Validation\" [readonly]=\"Readonly\" [submitted]=\"Form?.submitted\" type=\"text\" pattern=\"{{Pattern || '^([0-9]*[,])?[0-9]+$'}}\" [required]=\"Required\" [(ngModel)]=\"Model\" name=\"{{GeneratedName}}\" autocomplete=\"off\" (inputChange)=\"changed();\"></val-input>\r\n </div>\r\n <!--Se numero intero-->\r\n <div *ngIf=\"Type == 'int'\">\r\n <val-input #validationControl=\"ngModel\" [forceInvalid]=\"ForcedError\" [noValidate]=\"!Validation\" [readonly]=\"Readonly\" [submitted]=\"Form?.submitted\" type=\"text\" pattern=\"{{Pattern || '^[0-9]\\\\d*$'}}\" [required]=\"Required\" [(ngModel)]=\"Model\" name=\"{{GeneratedName}}\" autocomplete=\"off\" (inputChange)=\"changed();\"></val-input>\r\n </div>\r\n <!--Se boolean-->\r\n <div class=\"m-t-5\" *ngIf=\"Type == 'boolean'\">\r\n <input #validationControl=\"ngModel\" [readonly]=\"Readonly\" type=\"checkbox\" class=\"app-pointer\" [(ngModel)]=\"Model\" name=\"{{GeneratedName}}\" (ngModelChange)=\"changed();\" />\r\n </div>\r\n <!--Se enum-->\r\n <div *ngIf=\"Type == 'enum'\">\r\n <val-select #validationControl=\"ngModel\" [forceInvalid]=\"ForcedError\" [noValidate]=\"!Validation\" [readonly]=\"Readonly\" [submitted]=\"Form?.submitted\" [placeHolderValue]=\"''\" [placeholder]=\"Required ? ('Select' | localize : lc) + '...' : Placeholder\" [required]=\"Required\" [(ngModel)]=\"Model\" (inputChange)=\"changed();\" name=\"{{GeneratedName}}\">\r\n <option *ngFor=\"let val of BoundSource\" [value]=\"val.id\">{{val.description}}</option>\r\n </val-select>\r\n </div>\r\n <!--Se autocomplete-->\r\n <div *ngIf=\"Type == 'autocomplete'\">\r\n <val-autocomplete #validationControl=\"ngModel\" [forceInvalid]=\"ForcedError\" [noValidate]=\"!Validation\" [readonly]=\"Readonly\" [submitted]=\"Form?.submitted\" [required]=\"Required\" [placeholder]=\"Required ? ('Select' | localize : lc) + '...' : Placeholder\" [(ngModel)]=\"Model\" name=\"{{GeneratedName}}\" [FilteredSource]=\"FilteredBoundSource\" (inputChange)=\"filterSource($event); changed();\"></val-autocomplete>\r\n </div>\r\n <!--Se date time-->\r\n <div *ngIf=\"Type == 'datetime'\">\r\n <val-datetime #validationControl=\"ngModel\" [forceInvalid]=\"ForcedError\" [noValidate]=\"!Validation\" [readonly]=\"Readonly\" [submitted]=\"Form?.submitted\" [required]=\"Required\" [(ngModel)]=\"Model\" name=\"{{GeneratedName}}\" autocomplete=\"off\" (inputChange)=\"changed();\"></val-datetime>\r\n </div>\r\n <!--Se time-->\r\n <div *ngIf=\"Type == 'time'\">\r\n <ngx-mat-timepicker name=\"val-time\" #elementRef #baseInput=\"ngModel\" [(ngModel)]=\"Model\" [disabled]=\"Readonly\"\r\n [showSpinners]=\"false\" [stepHour]=\"2\" [stepMinute]=\"5\" [stepSecond]=\"30\"\r\n [showSeconds]=\"true\" (ngModelChange)=\"changed()\" #validationControl=\"ngModel\">\r\n </ngx-mat-timepicker>\r\n </div>\r\n <!--Se file-->\r\n <div *ngIf=\"Type == 'file'\">\r\n <div class=\"input-group file-upload\">\r\n <input type=\"file\" (change)=\"fileChange()\" #fileInput class=\"file-upload-btn app-pointer\" [multiple]=\"null\"/>\r\n <input type=\"text\" [class.frm-padding-left-22]=\"AllowDownload && ModelFile.filename && ModelFile.fileb64\" class=\"form-control checking-field\" placeholder=\"{{'Select a file' | localize : lc}}...\" [(ngModel)]=\"ModelFile.filename\" name=\"dsfile\" #validationControl=\"ngModel\" [required]=\"Required\"/>\r\n \r\n <a class=\"fa fa-download app-pointer app-input-icon\" *ngIf=\"AllowDownload && ModelFile.filename && ModelFile.fileb64\" (click)=\"downloadAttachment()\"></a>\r\n <i class=\"fa fa-times delete-file\" (click)=\"fileChange(true)\" *ngIf=\"ModelFile.filename\"></i>\r\n <span class=\"input-group-btn\">\r\n <button class=\"btn btn-primary btn-file-upload\" type=\"button\"><i class=\"fa fa-upload\"></i></button>\r\n </span>\r\n </div>\r\n </div>\r\n</ng-template>",
|
|
2080
2161
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
2081
2162
|
styles: [".frm-padding-left-22{padding-left:22px}\n"]
|
|
2082
2163
|
},] }
|
|
@@ -2101,7 +2182,8 @@ FormAdaptiveComponent.propDecorators = {
|
|
|
2101
2182
|
Precision: [{ type: Input }],
|
|
2102
2183
|
Alignment: [{ type: Input }],
|
|
2103
2184
|
SearchFunction: [{ type: Input }],
|
|
2104
|
-
MinChars: [{ type: Input }]
|
|
2185
|
+
MinChars: [{ type: Input }],
|
|
2186
|
+
CaseSensitive: [{ type: Input }]
|
|
2105
2187
|
};
|
|
2106
2188
|
|
|
2107
2189
|
// Angular
|
|
@@ -2185,7 +2267,7 @@ class FormTemplateComponent {
|
|
|
2185
2267
|
FormTemplateComponent.decorators = [
|
|
2186
2268
|
{ type: Component, args: [{
|
|
2187
2269
|
selector: "form-template",
|
|
2188
|
-
template: "<ng-container *ngIf=\"!FormLayout\">\r\n <ng-content></ng-content>\r\n</ng-container>\r\n\r\n<div *ngIf=\"FormLayout\" class=\"form-group row {{FormGroupClass}}\" [class.app-margin-bottom-0]=\"Last\">\r\n <label class=\"col-md-{{LabelColWidth}} m-t-5\">{{Label}}{{Required ? '*' : ''}}
|
|
2270
|
+
template: "<ng-container *ngIf=\"!FormLayout\">\r\n <ng-content></ng-content>\r\n</ng-container>\r\n\r\n<div *ngIf=\"FormLayout\" class=\"form-group row {{FormGroupClass}}\" [class.app-margin-bottom-0]=\"Last\">\r\n <label class=\"col-md-{{LabelColWidth}} m-t-5\">{{Label}}{{Required ? '*' : ''}}<span *ngIf=\"Label\">:</span></label>\r\n <div class=\"col-md-{{InputColWidth}}\">\r\n <ng-content></ng-content>\r\n </div>\r\n <div class=\"clearfix\"></div>\r\n</div>",
|
|
2189
2271
|
changeDetection: ChangeDetectionStrategy.OnPush
|
|
2190
2272
|
},] }
|
|
2191
2273
|
];
|
|
@@ -2653,7 +2735,8 @@ class FormMultiSelectComponent extends BaseFormControl {
|
|
|
2653
2735
|
text: this.SelectLabel || this.lc.loc("Select one or more values..."),
|
|
2654
2736
|
enableCheckAll: true,
|
|
2655
2737
|
disabled: disabled,
|
|
2656
|
-
labelKey: "description"
|
|
2738
|
+
labelKey: "description",
|
|
2739
|
+
tagToBody: false
|
|
2657
2740
|
};
|
|
2658
2741
|
}
|
|
2659
2742
|
/**
|
|
@@ -2808,11 +2891,19 @@ class FormAutocompleteComponent extends BaseFormControl {
|
|
|
2808
2891
|
* Override del placeholder per select requried
|
|
2809
2892
|
*/
|
|
2810
2893
|
this.RequiredPlaceholder = null;
|
|
2894
|
+
/**
|
|
2895
|
+
* Indica se i controlli devono essere effettuati tenendo conto del Case o meno. Vale solo qualora la **Source** fosse fornita
|
|
2896
|
+
*/
|
|
2897
|
+
this.CaseSensitive = false;
|
|
2811
2898
|
/**
|
|
2812
2899
|
* Indica se ignorare il prossimo evento writeValue che normalmente dovrebbe richiedere la nuova source. Serve per quando l'utente seleziona un elemento:
|
|
2813
2900
|
* Subito dopo partirebbe un altro evento modelChange che ricaricherebbe nuovamente la source
|
|
2814
2901
|
*/
|
|
2815
2902
|
this.ignoreNextWriteValue = false;
|
|
2903
|
+
/**
|
|
2904
|
+
* Sorgente Bindata Filtrata in base al contenuto della casella di testo
|
|
2905
|
+
*/
|
|
2906
|
+
this.FilteredBoundSource = [];
|
|
2816
2907
|
//******************** Funzione di throttling per non spammare richieste in caso di animazioni attivate
|
|
2817
2908
|
//TODO: spostarla in un metodo di utilità (esfaenza/extensions)
|
|
2818
2909
|
/** @ignore */
|
|
@@ -2822,16 +2913,27 @@ class FormAutocompleteComponent extends BaseFormControl {
|
|
|
2822
2913
|
* @ignore
|
|
2823
2914
|
*/
|
|
2824
2915
|
writeValue(value) {
|
|
2825
|
-
if (value)
|
|
2916
|
+
if (!value)
|
|
2917
|
+
return;
|
|
2918
|
+
if (this.SearchFunction) {
|
|
2826
2919
|
this.SearchFunction(value, true).subscribe(t => {
|
|
2827
2920
|
this.Source = t;
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
this.propagateChange(val ? val.id : value);
|
|
2831
|
-
this.Model = val ? val.description : value;
|
|
2832
|
-
});
|
|
2921
|
+
this.tryBindSourceDisplay();
|
|
2922
|
+
setTimeout(() => { this.finalizeValue(value); });
|
|
2833
2923
|
});
|
|
2924
|
+
return;
|
|
2834
2925
|
}
|
|
2926
|
+
this.finalizeValue(value);
|
|
2927
|
+
}
|
|
2928
|
+
/**
|
|
2929
|
+
* Dato un valore verifica se può restituire le informazioni trovate in **Source** con id uguale a **value** o se deve restituire il valore in se
|
|
2930
|
+
*
|
|
2931
|
+
* @param {any} value Valore scritto nell'input di testo
|
|
2932
|
+
*/
|
|
2933
|
+
finalizeValue(value) {
|
|
2934
|
+
var val = this.Source.find(t => t.id == value);
|
|
2935
|
+
this.propagateChange(val ? val.id : value);
|
|
2936
|
+
this.Model = val ? val.description : value;
|
|
2835
2937
|
}
|
|
2836
2938
|
/**
|
|
2837
2939
|
* Evento di filtro della sorgente dati in base all'input utente
|
|
@@ -2845,18 +2947,50 @@ class FormAutocompleteComponent extends BaseFormControl {
|
|
|
2845
2947
|
}
|
|
2846
2948
|
// Quando filtro la source, se non devo ignorare l'evento devo comunque assicurarmi di impostare il valore selezionato a null
|
|
2847
2949
|
super.changed("");
|
|
2950
|
+
if (!event && this.MinChars == 0 && !this.SearchFunction) {
|
|
2951
|
+
this.FilteredBoundSource = this.BoundSource;
|
|
2952
|
+
return;
|
|
2953
|
+
}
|
|
2848
2954
|
if (!event || event.length < this.MinChars) {
|
|
2849
|
-
this.
|
|
2955
|
+
this.FilteredBoundSource = [];
|
|
2850
2956
|
return;
|
|
2851
2957
|
}
|
|
2852
|
-
if (!this.SearchFunction)
|
|
2958
|
+
if (!this.SearchFunction && (!this.Source || this.Source.length == 0))
|
|
2853
2959
|
throw "Impossibile filtrare gli elementi senza una funzione di ricerca che restituisca una lista di { id: string, description: string }";
|
|
2854
|
-
this.
|
|
2855
|
-
this.
|
|
2856
|
-
this.
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2960
|
+
if (this.SearchFunction) {
|
|
2961
|
+
this.throttla("filtersource", () => {
|
|
2962
|
+
this.SearchFunction(event, false).subscribe(t => {
|
|
2963
|
+
this.Source = t;
|
|
2964
|
+
this.tryBindSourceDisplay();
|
|
2965
|
+
// In questo caso è già filtrata dalla SearchFunction
|
|
2966
|
+
this.FilteredBoundSource = this.BoundSource;
|
|
2967
|
+
this.cdr.markForCheck();
|
|
2968
|
+
});
|
|
2969
|
+
}, 400);
|
|
2970
|
+
}
|
|
2971
|
+
else {
|
|
2972
|
+
this.throttla("filtersource", () => {
|
|
2973
|
+
// In questo caso devo filtrare io in memoria
|
|
2974
|
+
this.FilteredBoundSource = this.BoundSource.filter(t => (this.CaseSensitive && t.description.includes(event)) || (!this.CaseSensitive && t.description.toLowerCase().includes(event.toLowerCase())));
|
|
2975
|
+
this.cdr.markForCheck();
|
|
2976
|
+
}, 100);
|
|
2977
|
+
}
|
|
2978
|
+
}
|
|
2979
|
+
/**
|
|
2980
|
+
* @ignore
|
|
2981
|
+
*/
|
|
2982
|
+
ngOnChanges(changes) {
|
|
2983
|
+
var _a;
|
|
2984
|
+
let newSource = changes["Source"];
|
|
2985
|
+
if (newSource) {
|
|
2986
|
+
this.tryBindSourceDisplay();
|
|
2987
|
+
// Prima assegnazione se cambia la source sotto (quindi se viene bindata direttamente da HTML)
|
|
2988
|
+
if ((((_a = this.Model) === null || _a === void 0 ? void 0 : _a.length) || 0) >= this.MinChars && !this.SearchFunction)
|
|
2989
|
+
this.FilteredBoundSource = this.BoundSource;
|
|
2990
|
+
else
|
|
2991
|
+
this.FilteredBoundSource = [];
|
|
2992
|
+
this.cdr.markForCheck();
|
|
2993
|
+
}
|
|
2860
2994
|
}
|
|
2861
2995
|
/**
|
|
2862
2996
|
* @ignore
|
|
@@ -2883,7 +3017,7 @@ class FormAutocompleteComponent extends BaseFormControl {
|
|
|
2883
3017
|
FormAutocompleteComponent.decorators = [
|
|
2884
3018
|
{ type: Component, args: [{
|
|
2885
3019
|
selector: "form-autocomplete",
|
|
2886
|
-
template: "<ng-container *ngIf=\"!FormLayout\">\r\n <ng-container *ngTemplateOutlet=\"controlTemplate\"></ng-container>\r\n</ng-container>\r\n\r\n<div *ngIf=\"FormLayout\" class=\"form-group row {{FormGroupClass}}\" [class.app-margin-bottom-0]=\"Last\">\r\n <label class=\"col-md-{{LabelColWidth}} m-t-5\">{{Label}}{{Required ? '*' : ''}}:</label>\r\n <div class=\"col-md-{{InputColWidth}}\">\r\n <ng-container *ngTemplateOutlet=\"controlTemplate\"></ng-container>\r\n </div>\r\n <div class=\"clearfix\"></div>\r\n</div>\r\n\r\n<ng-template #controlTemplate>\r\n <val-autocomplete [noValidate]=\"!Validation\"\r\n [submitted]=\"Form?.submitted\"\r\n [forceInvalid]=\"ForcedError\"\r\n [readonly]=\"Readonly\"\r\n [label]=\"SelectLabel\"\r\n type=\"text\"\r\n [(ngModel)]=\"Model\"\r\n name=\"{{GeneratedName}}\"\r\n #validationControl=\"ngModel\"\r\n (inputChange)=\"filterSource($event);\"\r\n (optionChange)=\"changed($event);\"\r\n [placeholder]=\"Required ? ((RequiredPlaceholder != null ? RequiredPlaceholder : ('Select' | localize : lc) + '...')) : Placeholder\"\r\n [validationFailed]=\"FailedValidationMessage\"\r\n [FilteredSource]=\"
|
|
3020
|
+
template: "<ng-container *ngIf=\"!FormLayout\">\r\n <ng-container *ngTemplateOutlet=\"controlTemplate\"></ng-container>\r\n</ng-container>\r\n\r\n<div *ngIf=\"FormLayout\" class=\"form-group row {{FormGroupClass}}\" [class.app-margin-bottom-0]=\"Last\">\r\n <label class=\"col-md-{{LabelColWidth}} m-t-5\">{{Label}}{{Required ? '*' : ''}}:</label>\r\n <div class=\"col-md-{{InputColWidth}}\">\r\n <ng-container *ngTemplateOutlet=\"controlTemplate\"></ng-container>\r\n </div>\r\n <div class=\"clearfix\"></div>\r\n</div>\r\n\r\n<ng-template #controlTemplate>\r\n <val-autocomplete [noValidate]=\"!Validation\"\r\n [submitted]=\"Form?.submitted\"\r\n [forceInvalid]=\"ForcedError\"\r\n [readonly]=\"Readonly\"\r\n [label]=\"SelectLabel\"\r\n type=\"text\"\r\n [(ngModel)]=\"Model\"\r\n name=\"{{GeneratedName}}\"\r\n #validationControl=\"ngModel\"\r\n (inputChange)=\"filterSource($event);\"\r\n (optionChange)=\"changed($event);\"\r\n [placeholder]=\"Required ? ((RequiredPlaceholder != null ? RequiredPlaceholder : ('Select' | localize : lc) + '...')) : Placeholder\"\r\n [validationFailed]=\"FailedValidationMessage\"\r\n [FilteredSource]=\"FilteredBoundSource\"\r\n >\r\n </val-autocomplete>\r\n</ng-template>",
|
|
2887
3021
|
providers: [{ provide: LocalizationService, useClass: FormAutocompleteComponentLoc }],
|
|
2888
3022
|
changeDetection: ChangeDetectionStrategy.OnPush
|
|
2889
3023
|
},] }
|
|
@@ -2901,7 +3035,8 @@ FormAutocompleteComponent.propDecorators = {
|
|
|
2901
3035
|
SelectLabel: [{ type: Input }],
|
|
2902
3036
|
SearchFunction: [{ type: Input }],
|
|
2903
3037
|
MinChars: [{ type: Input }],
|
|
2904
|
-
RequiredPlaceholder: [{ type: Input }]
|
|
3038
|
+
RequiredPlaceholder: [{ type: Input }],
|
|
3039
|
+
CaseSensitive: [{ type: Input }]
|
|
2905
3040
|
};
|
|
2906
3041
|
|
|
2907
3042
|
// Angular
|