@esfaenza/forms-and-validations 12.2.25 → 12.2.29
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 +214 -76
- 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/validations/validation-autocomplete/validation-autocomplete.component.js +1 -13
- package/esm2015/lib/validations/validation-date/validation-date.component.js +5 -3
- package/fesm2015/esfaenza-forms-and-validations.js +210 -73
- 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 +1 -1
|
@@ -961,8 +961,10 @@
|
|
|
961
961
|
var date = null;
|
|
962
962
|
if (this.useJsDates) {
|
|
963
963
|
date = this.dateExts.getDateConvertion(value);
|
|
964
|
-
|
|
965
|
-
|
|
964
|
+
if (date) {
|
|
965
|
+
this.propagateChange(date.toDate());
|
|
966
|
+
this.inputChange.emit(date.toDate());
|
|
967
|
+
}
|
|
966
968
|
}
|
|
967
969
|
else
|
|
968
970
|
date = dayjs(value, this.lc.token("getSmallDateFormat"));
|
|
@@ -1528,10 +1530,6 @@
|
|
|
1528
1530
|
* @ignore
|
|
1529
1531
|
*/
|
|
1530
1532
|
_this.onTouched = function () { }; //placeholder on touched function
|
|
1531
|
-
//******************** Funzione di throttling per non spammare richieste in caso di animazioni attivate
|
|
1532
|
-
//TODO: spostarla in un metodo di utilità (esfaenza/extensions)
|
|
1533
|
-
/** @ignore */
|
|
1534
|
-
_this.executionTimers = {};
|
|
1535
1533
|
return _this;
|
|
1536
1534
|
}
|
|
1537
1535
|
/**
|
|
@@ -1615,15 +1613,6 @@
|
|
|
1615
1613
|
ValidationAutocompleteComponent.prototype.registerOnTouched = function (fn) {
|
|
1616
1614
|
this.onTouched = fn;
|
|
1617
1615
|
};
|
|
1618
|
-
/** @ignore */
|
|
1619
|
-
ValidationAutocompleteComponent.prototype.throttla = function (id, func, throttleTime) {
|
|
1620
|
-
var _this = this;
|
|
1621
|
-
//Se ho la funzione che vuole eseguire ripulisco quel timeout
|
|
1622
|
-
if (this.executionTimers[id])
|
|
1623
|
-
clearTimeout(this.executionTimers[id]);
|
|
1624
|
-
//Ricreo il timeout per eseguire quella funzione dopo throttleTime millisecondi
|
|
1625
|
-
this.executionTimers[id] = setTimeout(function () { func(); _this.executionTimers[id] = null; }, throttleTime);
|
|
1626
|
-
};
|
|
1627
1616
|
return ValidationAutocompleteComponent;
|
|
1628
1617
|
}(BaseValidation));
|
|
1629
1618
|
ValidationAutocompleteComponent.decorators = [
|
|
@@ -1782,6 +1771,14 @@
|
|
|
1782
1771
|
* Evento chiamato alla modifica del valore collegato a questo campo
|
|
1783
1772
|
*/
|
|
1784
1773
|
this.inputChange = new core.EventEmitter();
|
|
1774
|
+
/**
|
|
1775
|
+
* Cache delle condizioni scritte tipo :prop?(Roba con {prop})
|
|
1776
|
+
*/
|
|
1777
|
+
this.BindCheckingGroups = [];
|
|
1778
|
+
/**
|
|
1779
|
+
* Cache delle proprietà scritte tipo --> {prop}
|
|
1780
|
+
*/
|
|
1781
|
+
this.BindProperties = [];
|
|
1785
1782
|
if (ngControl == null) {
|
|
1786
1783
|
if (!this.handleNullNgControl())
|
|
1787
1784
|
console.error("ngControl nullo per qualche motivo! Il 90% delle funzionalità di questo input saranno disabilitate");
|
|
@@ -1885,35 +1882,65 @@
|
|
|
1885
1882
|
// Cache locale per evitare di rifare dei regex.match ogni santa volta
|
|
1886
1883
|
if (this.Source.length > 0) {
|
|
1887
1884
|
this.BoundSource = [];
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
iffedMatches.forEach(function (m) {
|
|
1893
|
-
// Stessa regex di sopra ma il tag "i" serve per tirare fuori i singoli capturing group e per qualche motivo
|
|
1894
|
-
// new RegExp(baseRegex, "g") non funziona quindi non ho potuto razionalizzarlo
|
|
1895
|
-
var groups = m.match(/:([a-z]+)\?\(([^\(\)]+)\)/i);
|
|
1896
|
-
bindCheckingGroups.push({ global: m, prop: groups[1], whenexists: groups[2] });
|
|
1897
|
-
});
|
|
1898
|
-
}
|
|
1899
|
-
// Blocco per tirare fuori le proprietà scritte tipo --> {prop}
|
|
1900
|
-
var bindProperties = [];
|
|
1901
|
-
var matches = this.Display.match(/{[a-z]+}/gi);
|
|
1902
|
-
if (matches)
|
|
1903
|
-
matches.forEach(function (m) { bindProperties.push({ global: m, prop: m.substring(1, m.length - 1) }); });
|
|
1885
|
+
if (this.BindCheckingGroups.length == 0)
|
|
1886
|
+
this.evaluateBindCheckingGroups();
|
|
1887
|
+
if (this.BindProperties.length == 0)
|
|
1888
|
+
this.evaluateBindProperties();
|
|
1904
1889
|
// Blocco per generare la descrizione finale di un elemento
|
|
1905
1890
|
this.Source.forEach(function (s) {
|
|
1906
|
-
// Parto sempre dalla variabile di Display, poi sostituisco pezzo per pezzo
|
|
1907
|
-
var desc = _this.Display;
|
|
1908
|
-
// Taglio o mantengo le condizioni in base alla proprietà su cui fare check
|
|
1909
|
-
// Dopodiché scrivo tutte le proprietà
|
|
1910
|
-
bindCheckingGroups.forEach(function (t) { desc = desc.replace(t.global, (s[t.prop] != null && s[t.prop] != undefined) ? t.whenexists : ""); });
|
|
1911
|
-
bindProperties.forEach(function (t) { desc = desc.replace(t.global, s[t.prop]); });
|
|
1912
1891
|
// Aggiungo alla BoundSource in formato standard KeyValue
|
|
1913
|
-
_this.BoundSource.push(
|
|
1892
|
+
_this.BoundSource.push(_this.transformSourceItem(s));
|
|
1914
1893
|
});
|
|
1915
1894
|
}
|
|
1916
1895
|
};
|
|
1896
|
+
/**
|
|
1897
|
+
* Valuta il contenuto della variabile BindCheckingGroups
|
|
1898
|
+
*/
|
|
1899
|
+
BaseFormControl.prototype.evaluateBindCheckingGroups = function () {
|
|
1900
|
+
var _this = this;
|
|
1901
|
+
// Blocco per tirare fuori le condizioni scritte tipo --> :prop?(Roba con {prop})
|
|
1902
|
+
var iffedMatches = this.Display.match(/:([a-z]+)\?\(([^\(\)]+)\)/g);
|
|
1903
|
+
if (iffedMatches) {
|
|
1904
|
+
iffedMatches.forEach(function (m) {
|
|
1905
|
+
// Stessa regex di sopra ma il tag "i" serve per tirare fuori i singoli capturing group e per qualche motivo
|
|
1906
|
+
// new RegExp(baseRegex, "g") non funziona quindi non ho potuto razionalizzarlo
|
|
1907
|
+
var groups = m.match(/:([a-z]+)\?\(([^\(\)]+)\)/i);
|
|
1908
|
+
_this.BindCheckingGroups.push({ global: m, prop: groups[1], whenexists: groups[2] });
|
|
1909
|
+
});
|
|
1910
|
+
}
|
|
1911
|
+
};
|
|
1912
|
+
/**
|
|
1913
|
+
* Valuta il contenuto della variabile BindProperties
|
|
1914
|
+
*/
|
|
1915
|
+
BaseFormControl.prototype.evaluateBindProperties = function () {
|
|
1916
|
+
var _this = this;
|
|
1917
|
+
// Blocco per tirare fuori le proprietà scritte tipo --> {prop}
|
|
1918
|
+
var matches = this.Display.match(/{[a-z]+}/gi);
|
|
1919
|
+
if (matches)
|
|
1920
|
+
matches.forEach(function (m) { _this.BindProperties.push({ global: m, prop: m.substring(1, m.length - 1) }); });
|
|
1921
|
+
};
|
|
1922
|
+
/**
|
|
1923
|
+
* Trasforma un oggetto della Source alla sua versione "nuova" basandosi sulle informazioni su gruppi e proprietà
|
|
1924
|
+
*
|
|
1925
|
+
* @param {any} item Oggetto da trasformare
|
|
1926
|
+
*
|
|
1927
|
+
* @returns {{id: string, description: string}} Oggetto finale trasformato
|
|
1928
|
+
*/
|
|
1929
|
+
BaseFormControl.prototype.transformSourceItem = function (s) {
|
|
1930
|
+
// Parto sempre dalla variabile di Display, poi sostituisco pezzo per pezzo
|
|
1931
|
+
var desc = this.Display;
|
|
1932
|
+
// Taglio o mantengo le condizioni in base alla proprietà su cui fare check
|
|
1933
|
+
// Dopodiché scrivo tutte le proprietà
|
|
1934
|
+
for (var i = 0; i < this.BindCheckingGroups.length; i++) {
|
|
1935
|
+
var t = this.BindCheckingGroups[i];
|
|
1936
|
+
desc = desc.replace(t.global, (s[t.prop] != null && s[t.prop] != undefined) ? t.whenexists : "");
|
|
1937
|
+
}
|
|
1938
|
+
for (var i = 0; i < this.BindProperties.length; i++) {
|
|
1939
|
+
var t = this.BindProperties[i];
|
|
1940
|
+
desc = desc.replace(t.global, s[t.prop]);
|
|
1941
|
+
}
|
|
1942
|
+
return { id: s[this.IdField], description: desc };
|
|
1943
|
+
};
|
|
1917
1944
|
/**
|
|
1918
1945
|
* Indica se il comopnente in questione è in grado di gestire ngControl nulli.
|
|
1919
1946
|
* Di default è **false**
|
|
@@ -2322,10 +2349,23 @@
|
|
|
2322
2349
|
* Numero minimo di caratteri con cui cercare
|
|
2323
2350
|
*/
|
|
2324
2351
|
_this.MinChars = 3;
|
|
2352
|
+
/**
|
|
2353
|
+
* Indica se i controlli devono essere effettuati tenendo conto del Case o meno. Vale solo qualora la **Source** fosse fornita
|
|
2354
|
+
*/
|
|
2355
|
+
_this.CaseSensitive = false;
|
|
2325
2356
|
/**
|
|
2326
2357
|
* Variabile interna che gestisce se effettuare il riallineamento dei dati o meno
|
|
2327
2358
|
*/
|
|
2328
2359
|
_this.alignValues = false;
|
|
2360
|
+
/**
|
|
2361
|
+
* Indica se ignorare il prossimo evento writeValue che normalmente dovrebbe richiedere la nuova source. Serve per quando l'utente seleziona un elemento:
|
|
2362
|
+
* Subito dopo partirebbe un altro evento modelChange che ricaricherebbe nuovamente la source
|
|
2363
|
+
*/
|
|
2364
|
+
_this.ignoreNextWriteValue = false;
|
|
2365
|
+
/**
|
|
2366
|
+
* 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
|
|
2367
|
+
*/
|
|
2368
|
+
_this.FilteredBoundSource = [];
|
|
2329
2369
|
//******************** Funzione di throttling per non spammare richieste in caso di animazioni attivate
|
|
2330
2370
|
//TODO: spostarla in un metodo di utilità (esfaenza/extensions)
|
|
2331
2371
|
/** @ignore */
|
|
@@ -2337,13 +2377,21 @@
|
|
|
2337
2377
|
* @ignore
|
|
2338
2378
|
*/
|
|
2339
2379
|
FormAdaptiveComponent.prototype.ngOnChanges = function (changes) {
|
|
2380
|
+
var _a;
|
|
2340
2381
|
return __awaiter(this, void 0, void 0, function () {
|
|
2341
2382
|
var newSource, newType;
|
|
2342
|
-
return __generator(this, function (
|
|
2383
|
+
return __generator(this, function (_b) {
|
|
2343
2384
|
newSource = changes["Source"];
|
|
2344
2385
|
newType = changes["Type"];
|
|
2345
|
-
if (newSource)
|
|
2386
|
+
if (newSource) {
|
|
2346
2387
|
this.tryBindSourceDisplay();
|
|
2388
|
+
// Prima assegnazione se cambia la source sotto (quindi se viene bindata direttamente da HTML)
|
|
2389
|
+
if (this.Type == "autocomplete" && (((_a = this.Model) === null || _a === void 0 ? void 0 : _a.length) || 0) >= this.MinChars && !this.SearchFunction)
|
|
2390
|
+
this.FilteredBoundSource = this.BoundSource;
|
|
2391
|
+
else
|
|
2392
|
+
this.FilteredBoundSource = [];
|
|
2393
|
+
this.cdr.markForCheck();
|
|
2394
|
+
}
|
|
2347
2395
|
if (newType && this.Model)
|
|
2348
2396
|
this.writeValue(this.Model);
|
|
2349
2397
|
return [2 /*return*/];
|
|
@@ -2366,20 +2414,22 @@
|
|
|
2366
2414
|
this.alignValues = true;
|
|
2367
2415
|
}
|
|
2368
2416
|
if (this.Type == "time") {
|
|
2369
|
-
var
|
|
2417
|
+
var _b = __read((obj || "0:0:0").split(":"), 3), hours = _b[0], minutes = _b[1], seconds = _b[2];
|
|
2370
2418
|
obj = dayjs().hour(hours !== null && hours !== void 0 ? hours : 0).minute(minutes !== null && minutes !== void 0 ? minutes : 0).second(seconds !== null && seconds !== void 0 ? seconds : 0);
|
|
2371
2419
|
}
|
|
2372
2420
|
if (this.Type == "file")
|
|
2373
2421
|
obj = this.ModelFile;
|
|
2374
2422
|
if (this.Type == "autocomplete") {
|
|
2375
|
-
this.SearchFunction
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
_this.Model = val ? val.description : obj;
|
|
2423
|
+
if (this.SearchFunction) {
|
|
2424
|
+
this.SearchFunction(obj, true).subscribe(function (t) {
|
|
2425
|
+
_this.Source = t;
|
|
2426
|
+
_this.tryBindSourceDisplay();
|
|
2427
|
+
setTimeout(function () { _this.finalizeValue(obj); });
|
|
2381
2428
|
});
|
|
2382
|
-
|
|
2429
|
+
return;
|
|
2430
|
+
}
|
|
2431
|
+
else
|
|
2432
|
+
this.finalizeValue(obj);
|
|
2383
2433
|
}
|
|
2384
2434
|
_super.prototype.writeValue.call(this, obj);
|
|
2385
2435
|
if (this.alignValues) {
|
|
@@ -2387,6 +2437,16 @@
|
|
|
2387
2437
|
this.cdr.markForCheck();
|
|
2388
2438
|
}
|
|
2389
2439
|
};
|
|
2440
|
+
/**
|
|
2441
|
+
* 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
|
|
2442
|
+
*
|
|
2443
|
+
* @param {any} value Valore scritto nell'input di testo
|
|
2444
|
+
*/
|
|
2445
|
+
FormAdaptiveComponent.prototype.finalizeValue = function (value) {
|
|
2446
|
+
var val = this.Source.find(function (t) { return t.id == value; });
|
|
2447
|
+
this.propagateChange(val ? val.id : value);
|
|
2448
|
+
this.Model = val ? val.description : value;
|
|
2449
|
+
};
|
|
2390
2450
|
/**
|
|
2391
2451
|
* Evento di filtro della sorgente dati in base all'input utente
|
|
2392
2452
|
*
|
|
@@ -2394,18 +2454,40 @@
|
|
|
2394
2454
|
*/
|
|
2395
2455
|
FormAdaptiveComponent.prototype.filterSource = function (event) {
|
|
2396
2456
|
var _this = this;
|
|
2397
|
-
if (
|
|
2398
|
-
this.
|
|
2457
|
+
if (this.ignoreNextWriteValue) {
|
|
2458
|
+
this.ignoreNextWriteValue = false;
|
|
2459
|
+
return;
|
|
2460
|
+
}
|
|
2461
|
+
// Quando filtro la source, se non devo ignorare l'evento devo comunque assicurarmi di impostare il valore selezionato a null
|
|
2462
|
+
_super.prototype.changed.call(this, "");
|
|
2463
|
+
if (!event && this.MinChars == 0 && !this.SearchFunction) {
|
|
2464
|
+
this.FilteredBoundSource = this.BoundSource;
|
|
2399
2465
|
return;
|
|
2400
2466
|
}
|
|
2401
|
-
if (!this.
|
|
2467
|
+
if (!event || event.length < this.MinChars) {
|
|
2468
|
+
this.FilteredBoundSource = [];
|
|
2469
|
+
return;
|
|
2470
|
+
}
|
|
2471
|
+
if (!this.SearchFunction && (!this.Source || this.Source.length == 0))
|
|
2402
2472
|
throw "Impossibile filtrare gli elementi senza una funzione di ricerca che restituisca una lista di { id: string, description: string }";
|
|
2403
|
-
this.
|
|
2404
|
-
|
|
2405
|
-
_this.
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2473
|
+
if (this.SearchFunction) {
|
|
2474
|
+
this.throttla("filtersource", function () {
|
|
2475
|
+
_this.SearchFunction(event, false).subscribe(function (t) {
|
|
2476
|
+
_this.Source = t;
|
|
2477
|
+
_this.tryBindSourceDisplay();
|
|
2478
|
+
// In questo caso è già filtrata dalla SearchFunction
|
|
2479
|
+
_this.FilteredBoundSource = _this.BoundSource;
|
|
2480
|
+
_this.cdr.markForCheck();
|
|
2481
|
+
});
|
|
2482
|
+
}, 400);
|
|
2483
|
+
}
|
|
2484
|
+
else {
|
|
2485
|
+
this.throttla("filtersource", function () {
|
|
2486
|
+
// In questo caso devo filtrare io in memoria
|
|
2487
|
+
_this.FilteredBoundSource = _this.BoundSource.filter(function (t) { return (_this.CaseSensitive && t.description.includes(event)) || (!_this.CaseSensitive && t.description.toLowerCase().includes(event.toLowerCase())); });
|
|
2488
|
+
_this.cdr.markForCheck();
|
|
2489
|
+
}, 100);
|
|
2490
|
+
}
|
|
2409
2491
|
};
|
|
2410
2492
|
/**
|
|
2411
2493
|
* Metodo richiamato quando viene modificato il modello del campo di input
|
|
@@ -2420,6 +2502,8 @@
|
|
|
2420
2502
|
var toEmit = this.dateAdapter.clone(this.Model);
|
|
2421
2503
|
toEmit = toEmit.format("HH:mm:ss");
|
|
2422
2504
|
}
|
|
2505
|
+
if (this.Type == "autocomplete")
|
|
2506
|
+
this.ignoreNextWriteValue = true;
|
|
2423
2507
|
_super.prototype.changed.call(this, toEmit);
|
|
2424
2508
|
};
|
|
2425
2509
|
/**
|
|
@@ -2474,7 +2558,7 @@
|
|
|
2474
2558
|
{ type: core.Component, args: [{
|
|
2475
2559
|
selector: "form-adaptive",
|
|
2476
2560
|
providers: [{ provide: localizations.LocalizationService, useClass: FormAdaptiveComponentLoc }],
|
|
2477
|
-
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]=\"
|
|
2561
|
+
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>",
|
|
2478
2562
|
changeDetection: core.ChangeDetectionStrategy.OnPush,
|
|
2479
2563
|
styles: [".frm-padding-left-22{padding-left:22px}\n"]
|
|
2480
2564
|
},] }
|
|
@@ -2499,7 +2583,8 @@
|
|
|
2499
2583
|
Precision: [{ type: core.Input }],
|
|
2500
2584
|
Alignment: [{ type: core.Input }],
|
|
2501
2585
|
SearchFunction: [{ type: core.Input }],
|
|
2502
|
-
MinChars: [{ type: core.Input }]
|
|
2586
|
+
MinChars: [{ type: core.Input }],
|
|
2587
|
+
CaseSensitive: [{ type: core.Input }]
|
|
2503
2588
|
};
|
|
2504
2589
|
|
|
2505
2590
|
// Angular
|
|
@@ -3086,7 +3171,8 @@
|
|
|
3086
3171
|
text: this.SelectLabel || this.lc.loc("Select one or more values..."),
|
|
3087
3172
|
enableCheckAll: true,
|
|
3088
3173
|
disabled: disabled,
|
|
3089
|
-
labelKey: "description"
|
|
3174
|
+
labelKey: "description",
|
|
3175
|
+
tagToBody: false
|
|
3090
3176
|
};
|
|
3091
3177
|
};
|
|
3092
3178
|
/**
|
|
@@ -3246,11 +3332,19 @@
|
|
|
3246
3332
|
* Override del placeholder per select requried
|
|
3247
3333
|
*/
|
|
3248
3334
|
_this.RequiredPlaceholder = null;
|
|
3335
|
+
/**
|
|
3336
|
+
* Indica se i controlli devono essere effettuati tenendo conto del Case o meno. Vale solo qualora la **Source** fosse fornita
|
|
3337
|
+
*/
|
|
3338
|
+
_this.CaseSensitive = false;
|
|
3249
3339
|
/**
|
|
3250
3340
|
* Indica se ignorare il prossimo evento writeValue che normalmente dovrebbe richiedere la nuova source. Serve per quando l'utente seleziona un elemento:
|
|
3251
3341
|
* Subito dopo partirebbe un altro evento modelChange che ricaricherebbe nuovamente la source
|
|
3252
3342
|
*/
|
|
3253
3343
|
_this.ignoreNextWriteValue = false;
|
|
3344
|
+
/**
|
|
3345
|
+
* Sorgente Bindata Filtrata in base al contenuto della casella di testo
|
|
3346
|
+
*/
|
|
3347
|
+
_this.FilteredBoundSource = [];
|
|
3254
3348
|
//******************** Funzione di throttling per non spammare richieste in caso di animazioni attivate
|
|
3255
3349
|
//TODO: spostarla in un metodo di utilità (esfaenza/extensions)
|
|
3256
3350
|
/** @ignore */
|
|
@@ -3262,16 +3356,27 @@
|
|
|
3262
3356
|
*/
|
|
3263
3357
|
FormAutocompleteComponent.prototype.writeValue = function (value) {
|
|
3264
3358
|
var _this = this;
|
|
3265
|
-
if (value)
|
|
3359
|
+
if (!value)
|
|
3360
|
+
return;
|
|
3361
|
+
if (this.SearchFunction) {
|
|
3266
3362
|
this.SearchFunction(value, true).subscribe(function (t) {
|
|
3267
3363
|
_this.Source = t;
|
|
3268
|
-
|
|
3269
|
-
|
|
3270
|
-
_this.propagateChange(val ? val.id : value);
|
|
3271
|
-
_this.Model = val ? val.description : value;
|
|
3272
|
-
});
|
|
3364
|
+
_this.tryBindSourceDisplay();
|
|
3365
|
+
setTimeout(function () { _this.finalizeValue(value); });
|
|
3273
3366
|
});
|
|
3367
|
+
return;
|
|
3274
3368
|
}
|
|
3369
|
+
this.finalizeValue(value);
|
|
3370
|
+
};
|
|
3371
|
+
/**
|
|
3372
|
+
* 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
|
|
3373
|
+
*
|
|
3374
|
+
* @param {any} value Valore scritto nell'input di testo
|
|
3375
|
+
*/
|
|
3376
|
+
FormAutocompleteComponent.prototype.finalizeValue = function (value) {
|
|
3377
|
+
var val = this.Source.find(function (t) { return t.id == value; });
|
|
3378
|
+
this.propagateChange(val ? val.id : value);
|
|
3379
|
+
this.Model = val ? val.description : value;
|
|
3275
3380
|
};
|
|
3276
3381
|
/**
|
|
3277
3382
|
* Evento di filtro della sorgente dati in base all'input utente
|
|
@@ -3286,18 +3391,50 @@
|
|
|
3286
3391
|
}
|
|
3287
3392
|
// Quando filtro la source, se non devo ignorare l'evento devo comunque assicurarmi di impostare il valore selezionato a null
|
|
3288
3393
|
_super.prototype.changed.call(this, "");
|
|
3394
|
+
if (!event && this.MinChars == 0 && !this.SearchFunction) {
|
|
3395
|
+
this.FilteredBoundSource = this.BoundSource;
|
|
3396
|
+
return;
|
|
3397
|
+
}
|
|
3289
3398
|
if (!event || event.length < this.MinChars) {
|
|
3290
|
-
this.
|
|
3399
|
+
this.FilteredBoundSource = [];
|
|
3291
3400
|
return;
|
|
3292
3401
|
}
|
|
3293
|
-
if (!this.SearchFunction)
|
|
3402
|
+
if (!this.SearchFunction && (!this.Source || this.Source.length == 0))
|
|
3294
3403
|
throw "Impossibile filtrare gli elementi senza una funzione di ricerca che restituisca una lista di { id: string, description: string }";
|
|
3295
|
-
this.
|
|
3296
|
-
|
|
3297
|
-
_this.
|
|
3298
|
-
|
|
3299
|
-
|
|
3300
|
-
|
|
3404
|
+
if (this.SearchFunction) {
|
|
3405
|
+
this.throttla("filtersource", function () {
|
|
3406
|
+
_this.SearchFunction(event, false).subscribe(function (t) {
|
|
3407
|
+
_this.Source = t;
|
|
3408
|
+
_this.tryBindSourceDisplay();
|
|
3409
|
+
// In questo caso è già filtrata dalla SearchFunction
|
|
3410
|
+
_this.FilteredBoundSource = _this.BoundSource;
|
|
3411
|
+
_this.cdr.markForCheck();
|
|
3412
|
+
});
|
|
3413
|
+
}, 400);
|
|
3414
|
+
}
|
|
3415
|
+
else {
|
|
3416
|
+
this.throttla("filtersource", function () {
|
|
3417
|
+
// In questo caso devo filtrare io in memoria
|
|
3418
|
+
_this.FilteredBoundSource = _this.BoundSource.filter(function (t) { return (_this.CaseSensitive && t.description.includes(event)) || (!_this.CaseSensitive && t.description.toLowerCase().includes(event.toLowerCase())); });
|
|
3419
|
+
_this.cdr.markForCheck();
|
|
3420
|
+
}, 100);
|
|
3421
|
+
}
|
|
3422
|
+
};
|
|
3423
|
+
/**
|
|
3424
|
+
* @ignore
|
|
3425
|
+
*/
|
|
3426
|
+
FormAutocompleteComponent.prototype.ngOnChanges = function (changes) {
|
|
3427
|
+
var _a;
|
|
3428
|
+
var newSource = changes["Source"];
|
|
3429
|
+
if (newSource) {
|
|
3430
|
+
this.tryBindSourceDisplay();
|
|
3431
|
+
// Prima assegnazione se cambia la source sotto (quindi se viene bindata direttamente da HTML)
|
|
3432
|
+
if ((((_a = this.Model) === null || _a === void 0 ? void 0 : _a.length) || 0) >= this.MinChars && !this.SearchFunction)
|
|
3433
|
+
this.FilteredBoundSource = this.BoundSource;
|
|
3434
|
+
else
|
|
3435
|
+
this.FilteredBoundSource = [];
|
|
3436
|
+
this.cdr.markForCheck();
|
|
3437
|
+
}
|
|
3301
3438
|
};
|
|
3302
3439
|
/**
|
|
3303
3440
|
* @ignore
|
|
@@ -3328,7 +3465,7 @@
|
|
|
3328
3465
|
FormAutocompleteComponent.decorators = [
|
|
3329
3466
|
{ type: core.Component, args: [{
|
|
3330
3467
|
selector: "form-autocomplete",
|
|
3331
|
-
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]=\"
|
|
3468
|
+
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>",
|
|
3332
3469
|
providers: [{ provide: localizations.LocalizationService, useClass: FormAutocompleteComponentLoc }],
|
|
3333
3470
|
changeDetection: core.ChangeDetectionStrategy.OnPush
|
|
3334
3471
|
},] }
|
|
@@ -3346,7 +3483,8 @@
|
|
|
3346
3483
|
SelectLabel: [{ type: core.Input }],
|
|
3347
3484
|
SearchFunction: [{ type: core.Input }],
|
|
3348
3485
|
MinChars: [{ type: core.Input }],
|
|
3349
|
-
RequiredPlaceholder: [{ type: core.Input }]
|
|
3486
|
+
RequiredPlaceholder: [{ type: core.Input }],
|
|
3487
|
+
CaseSensitive: [{ type: core.Input }]
|
|
3350
3488
|
};
|
|
3351
3489
|
|
|
3352
3490
|
/**
|