@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
|
@@ -1530,10 +1530,6 @@
|
|
|
1530
1530
|
* @ignore
|
|
1531
1531
|
*/
|
|
1532
1532
|
_this.onTouched = function () { }; //placeholder on touched function
|
|
1533
|
-
//******************** Funzione di throttling per non spammare richieste in caso di animazioni attivate
|
|
1534
|
-
//TODO: spostarla in un metodo di utilità (esfaenza/extensions)
|
|
1535
|
-
/** @ignore */
|
|
1536
|
-
_this.executionTimers = {};
|
|
1537
1533
|
return _this;
|
|
1538
1534
|
}
|
|
1539
1535
|
/**
|
|
@@ -1617,15 +1613,6 @@
|
|
|
1617
1613
|
ValidationAutocompleteComponent.prototype.registerOnTouched = function (fn) {
|
|
1618
1614
|
this.onTouched = fn;
|
|
1619
1615
|
};
|
|
1620
|
-
/** @ignore */
|
|
1621
|
-
ValidationAutocompleteComponent.prototype.throttla = function (id, func, throttleTime) {
|
|
1622
|
-
var _this = this;
|
|
1623
|
-
//Se ho la funzione che vuole eseguire ripulisco quel timeout
|
|
1624
|
-
if (this.executionTimers[id])
|
|
1625
|
-
clearTimeout(this.executionTimers[id]);
|
|
1626
|
-
//Ricreo il timeout per eseguire quella funzione dopo throttleTime millisecondi
|
|
1627
|
-
this.executionTimers[id] = setTimeout(function () { func(); _this.executionTimers[id] = null; }, throttleTime);
|
|
1628
|
-
};
|
|
1629
1616
|
return ValidationAutocompleteComponent;
|
|
1630
1617
|
}(BaseValidation));
|
|
1631
1618
|
ValidationAutocompleteComponent.decorators = [
|
|
@@ -1784,6 +1771,14 @@
|
|
|
1784
1771
|
* Evento chiamato alla modifica del valore collegato a questo campo
|
|
1785
1772
|
*/
|
|
1786
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 = [];
|
|
1787
1782
|
if (ngControl == null) {
|
|
1788
1783
|
if (!this.handleNullNgControl())
|
|
1789
1784
|
console.error("ngControl nullo per qualche motivo! Il 90% delle funzionalità di questo input saranno disabilitate");
|
|
@@ -1887,35 +1882,65 @@
|
|
|
1887
1882
|
// Cache locale per evitare di rifare dei regex.match ogni santa volta
|
|
1888
1883
|
if (this.Source.length > 0) {
|
|
1889
1884
|
this.BoundSource = [];
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
iffedMatches.forEach(function (m) {
|
|
1895
|
-
// Stessa regex di sopra ma il tag "i" serve per tirare fuori i singoli capturing group e per qualche motivo
|
|
1896
|
-
// new RegExp(baseRegex, "g") non funziona quindi non ho potuto razionalizzarlo
|
|
1897
|
-
var groups = m.match(/:([a-z]+)\?\(([^\(\)]+)\)/i);
|
|
1898
|
-
bindCheckingGroups.push({ global: m, prop: groups[1], whenexists: groups[2] });
|
|
1899
|
-
});
|
|
1900
|
-
}
|
|
1901
|
-
// Blocco per tirare fuori le proprietà scritte tipo --> {prop}
|
|
1902
|
-
var bindProperties = [];
|
|
1903
|
-
var matches = this.Display.match(/{[a-z]+}/gi);
|
|
1904
|
-
if (matches)
|
|
1905
|
-
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();
|
|
1906
1889
|
// Blocco per generare la descrizione finale di un elemento
|
|
1907
1890
|
this.Source.forEach(function (s) {
|
|
1908
|
-
// Parto sempre dalla variabile di Display, poi sostituisco pezzo per pezzo
|
|
1909
|
-
var desc = _this.Display;
|
|
1910
|
-
// Taglio o mantengo le condizioni in base alla proprietà su cui fare check
|
|
1911
|
-
// Dopodiché scrivo tutte le proprietà
|
|
1912
|
-
bindCheckingGroups.forEach(function (t) { desc = desc.replace(t.global, (s[t.prop] != null && s[t.prop] != undefined) ? t.whenexists : ""); });
|
|
1913
|
-
bindProperties.forEach(function (t) { desc = desc.replace(t.global, s[t.prop]); });
|
|
1914
1891
|
// Aggiungo alla BoundSource in formato standard KeyValue
|
|
1915
|
-
_this.BoundSource.push(
|
|
1892
|
+
_this.BoundSource.push(_this.transformSourceItem(s));
|
|
1916
1893
|
});
|
|
1917
1894
|
}
|
|
1918
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
|
+
};
|
|
1919
1944
|
/**
|
|
1920
1945
|
* Indica se il comopnente in questione è in grado di gestire ngControl nulli.
|
|
1921
1946
|
* Di default è **false**
|
|
@@ -2324,10 +2349,23 @@
|
|
|
2324
2349
|
* Numero minimo di caratteri con cui cercare
|
|
2325
2350
|
*/
|
|
2326
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;
|
|
2327
2356
|
/**
|
|
2328
2357
|
* Variabile interna che gestisce se effettuare il riallineamento dei dati o meno
|
|
2329
2358
|
*/
|
|
2330
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 = [];
|
|
2331
2369
|
//******************** Funzione di throttling per non spammare richieste in caso di animazioni attivate
|
|
2332
2370
|
//TODO: spostarla in un metodo di utilità (esfaenza/extensions)
|
|
2333
2371
|
/** @ignore */
|
|
@@ -2339,13 +2377,21 @@
|
|
|
2339
2377
|
* @ignore
|
|
2340
2378
|
*/
|
|
2341
2379
|
FormAdaptiveComponent.prototype.ngOnChanges = function (changes) {
|
|
2380
|
+
var _a;
|
|
2342
2381
|
return __awaiter(this, void 0, void 0, function () {
|
|
2343
2382
|
var newSource, newType;
|
|
2344
|
-
return __generator(this, function (
|
|
2383
|
+
return __generator(this, function (_b) {
|
|
2345
2384
|
newSource = changes["Source"];
|
|
2346
2385
|
newType = changes["Type"];
|
|
2347
|
-
if (newSource)
|
|
2386
|
+
if (newSource) {
|
|
2348
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
|
+
}
|
|
2349
2395
|
if (newType && this.Model)
|
|
2350
2396
|
this.writeValue(this.Model);
|
|
2351
2397
|
return [2 /*return*/];
|
|
@@ -2368,20 +2414,22 @@
|
|
|
2368
2414
|
this.alignValues = true;
|
|
2369
2415
|
}
|
|
2370
2416
|
if (this.Type == "time") {
|
|
2371
|
-
var
|
|
2417
|
+
var _b = __read((obj || "0:0:0").split(":"), 3), hours = _b[0], minutes = _b[1], seconds = _b[2];
|
|
2372
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);
|
|
2373
2419
|
}
|
|
2374
2420
|
if (this.Type == "file")
|
|
2375
2421
|
obj = this.ModelFile;
|
|
2376
2422
|
if (this.Type == "autocomplete") {
|
|
2377
|
-
this.SearchFunction
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
_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); });
|
|
2383
2428
|
});
|
|
2384
|
-
|
|
2429
|
+
return;
|
|
2430
|
+
}
|
|
2431
|
+
else
|
|
2432
|
+
this.finalizeValue(obj);
|
|
2385
2433
|
}
|
|
2386
2434
|
_super.prototype.writeValue.call(this, obj);
|
|
2387
2435
|
if (this.alignValues) {
|
|
@@ -2389,6 +2437,16 @@
|
|
|
2389
2437
|
this.cdr.markForCheck();
|
|
2390
2438
|
}
|
|
2391
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
|
+
};
|
|
2392
2450
|
/**
|
|
2393
2451
|
* Evento di filtro della sorgente dati in base all'input utente
|
|
2394
2452
|
*
|
|
@@ -2396,18 +2454,40 @@
|
|
|
2396
2454
|
*/
|
|
2397
2455
|
FormAdaptiveComponent.prototype.filterSource = function (event) {
|
|
2398
2456
|
var _this = this;
|
|
2399
|
-
if (
|
|
2400
|
-
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;
|
|
2465
|
+
return;
|
|
2466
|
+
}
|
|
2467
|
+
if (!event || event.length < this.MinChars) {
|
|
2468
|
+
this.FilteredBoundSource = [];
|
|
2401
2469
|
return;
|
|
2402
2470
|
}
|
|
2403
|
-
if (!this.SearchFunction)
|
|
2471
|
+
if (!this.SearchFunction && (!this.Source || this.Source.length == 0))
|
|
2404
2472
|
throw "Impossibile filtrare gli elementi senza una funzione di ricerca che restituisca una lista di { id: string, description: string }";
|
|
2405
|
-
this.
|
|
2406
|
-
|
|
2407
|
-
_this.
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
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
|
+
}
|
|
2411
2491
|
};
|
|
2412
2492
|
/**
|
|
2413
2493
|
* Metodo richiamato quando viene modificato il modello del campo di input
|
|
@@ -2422,6 +2502,8 @@
|
|
|
2422
2502
|
var toEmit = this.dateAdapter.clone(this.Model);
|
|
2423
2503
|
toEmit = toEmit.format("HH:mm:ss");
|
|
2424
2504
|
}
|
|
2505
|
+
if (this.Type == "autocomplete")
|
|
2506
|
+
this.ignoreNextWriteValue = true;
|
|
2425
2507
|
_super.prototype.changed.call(this, toEmit);
|
|
2426
2508
|
};
|
|
2427
2509
|
/**
|
|
@@ -2476,7 +2558,7 @@
|
|
|
2476
2558
|
{ type: core.Component, args: [{
|
|
2477
2559
|
selector: "form-adaptive",
|
|
2478
2560
|
providers: [{ provide: localizations.LocalizationService, useClass: FormAdaptiveComponentLoc }],
|
|
2479
|
-
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>",
|
|
2480
2562
|
changeDetection: core.ChangeDetectionStrategy.OnPush,
|
|
2481
2563
|
styles: [".frm-padding-left-22{padding-left:22px}\n"]
|
|
2482
2564
|
},] }
|
|
@@ -2501,7 +2583,8 @@
|
|
|
2501
2583
|
Precision: [{ type: core.Input }],
|
|
2502
2584
|
Alignment: [{ type: core.Input }],
|
|
2503
2585
|
SearchFunction: [{ type: core.Input }],
|
|
2504
|
-
MinChars: [{ type: core.Input }]
|
|
2586
|
+
MinChars: [{ type: core.Input }],
|
|
2587
|
+
CaseSensitive: [{ type: core.Input }]
|
|
2505
2588
|
};
|
|
2506
2589
|
|
|
2507
2590
|
// Angular
|
|
@@ -2591,7 +2674,7 @@
|
|
|
2591
2674
|
FormTemplateComponent.decorators = [
|
|
2592
2675
|
{ type: core.Component, args: [{
|
|
2593
2676
|
selector: "form-template",
|
|
2594
|
-
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 ? '*' : ''}}
|
|
2677
|
+
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>",
|
|
2595
2678
|
changeDetection: core.ChangeDetectionStrategy.OnPush
|
|
2596
2679
|
},] }
|
|
2597
2680
|
];
|
|
@@ -3088,7 +3171,8 @@
|
|
|
3088
3171
|
text: this.SelectLabel || this.lc.loc("Select one or more values..."),
|
|
3089
3172
|
enableCheckAll: true,
|
|
3090
3173
|
disabled: disabled,
|
|
3091
|
-
labelKey: "description"
|
|
3174
|
+
labelKey: "description",
|
|
3175
|
+
tagToBody: false
|
|
3092
3176
|
};
|
|
3093
3177
|
};
|
|
3094
3178
|
/**
|
|
@@ -3248,11 +3332,19 @@
|
|
|
3248
3332
|
* Override del placeholder per select requried
|
|
3249
3333
|
*/
|
|
3250
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;
|
|
3251
3339
|
/**
|
|
3252
3340
|
* Indica se ignorare il prossimo evento writeValue che normalmente dovrebbe richiedere la nuova source. Serve per quando l'utente seleziona un elemento:
|
|
3253
3341
|
* Subito dopo partirebbe un altro evento modelChange che ricaricherebbe nuovamente la source
|
|
3254
3342
|
*/
|
|
3255
3343
|
_this.ignoreNextWriteValue = false;
|
|
3344
|
+
/**
|
|
3345
|
+
* Sorgente Bindata Filtrata in base al contenuto della casella di testo
|
|
3346
|
+
*/
|
|
3347
|
+
_this.FilteredBoundSource = [];
|
|
3256
3348
|
//******************** Funzione di throttling per non spammare richieste in caso di animazioni attivate
|
|
3257
3349
|
//TODO: spostarla in un metodo di utilità (esfaenza/extensions)
|
|
3258
3350
|
/** @ignore */
|
|
@@ -3264,16 +3356,27 @@
|
|
|
3264
3356
|
*/
|
|
3265
3357
|
FormAutocompleteComponent.prototype.writeValue = function (value) {
|
|
3266
3358
|
var _this = this;
|
|
3267
|
-
if (value)
|
|
3359
|
+
if (!value)
|
|
3360
|
+
return;
|
|
3361
|
+
if (this.SearchFunction) {
|
|
3268
3362
|
this.SearchFunction(value, true).subscribe(function (t) {
|
|
3269
3363
|
_this.Source = t;
|
|
3270
|
-
|
|
3271
|
-
|
|
3272
|
-
_this.propagateChange(val ? val.id : value);
|
|
3273
|
-
_this.Model = val ? val.description : value;
|
|
3274
|
-
});
|
|
3364
|
+
_this.tryBindSourceDisplay();
|
|
3365
|
+
setTimeout(function () { _this.finalizeValue(value); });
|
|
3275
3366
|
});
|
|
3367
|
+
return;
|
|
3276
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;
|
|
3277
3380
|
};
|
|
3278
3381
|
/**
|
|
3279
3382
|
* Evento di filtro della sorgente dati in base all'input utente
|
|
@@ -3288,18 +3391,50 @@
|
|
|
3288
3391
|
}
|
|
3289
3392
|
// Quando filtro la source, se non devo ignorare l'evento devo comunque assicurarmi di impostare il valore selezionato a null
|
|
3290
3393
|
_super.prototype.changed.call(this, "");
|
|
3394
|
+
if (!event && this.MinChars == 0 && !this.SearchFunction) {
|
|
3395
|
+
this.FilteredBoundSource = this.BoundSource;
|
|
3396
|
+
return;
|
|
3397
|
+
}
|
|
3291
3398
|
if (!event || event.length < this.MinChars) {
|
|
3292
|
-
this.
|
|
3399
|
+
this.FilteredBoundSource = [];
|
|
3293
3400
|
return;
|
|
3294
3401
|
}
|
|
3295
|
-
if (!this.SearchFunction)
|
|
3402
|
+
if (!this.SearchFunction && (!this.Source || this.Source.length == 0))
|
|
3296
3403
|
throw "Impossibile filtrare gli elementi senza una funzione di ricerca che restituisca una lista di { id: string, description: string }";
|
|
3297
|
-
this.
|
|
3298
|
-
|
|
3299
|
-
_this.
|
|
3300
|
-
|
|
3301
|
-
|
|
3302
|
-
|
|
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
|
+
}
|
|
3303
3438
|
};
|
|
3304
3439
|
/**
|
|
3305
3440
|
* @ignore
|
|
@@ -3330,7 +3465,7 @@
|
|
|
3330
3465
|
FormAutocompleteComponent.decorators = [
|
|
3331
3466
|
{ type: core.Component, args: [{
|
|
3332
3467
|
selector: "form-autocomplete",
|
|
3333
|
-
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>",
|
|
3334
3469
|
providers: [{ provide: localizations.LocalizationService, useClass: FormAutocompleteComponentLoc }],
|
|
3335
3470
|
changeDetection: core.ChangeDetectionStrategy.OnPush
|
|
3336
3471
|
},] }
|
|
@@ -3348,7 +3483,8 @@
|
|
|
3348
3483
|
SelectLabel: [{ type: core.Input }],
|
|
3349
3484
|
SearchFunction: [{ type: core.Input }],
|
|
3350
3485
|
MinChars: [{ type: core.Input }],
|
|
3351
|
-
RequiredPlaceholder: [{ type: core.Input }]
|
|
3486
|
+
RequiredPlaceholder: [{ type: core.Input }],
|
|
3487
|
+
CaseSensitive: [{ type: core.Input }]
|
|
3352
3488
|
};
|
|
3353
3489
|
|
|
3354
3490
|
/**
|