@c10t/nice-component-library
Version:
nice-component-library
9,446 lines • 522 kB
JavaScript
import * as i1$2 from '@angular/forms';
import { FormGroup, FormArray, FormControl, Validators, NgControl, NG_VALUE_ACCESSOR, FormsModule, ReactiveFormsModule } from '@angular/forms';
import * as i1$3 from '@angular/common/http';
import { HttpParams, HttpHeaders, HttpResponse, HttpResponseBase } from '@angular/common/http';
import * as i0 from '@angular/core';
import { InjectionToken, Self, Optional, Inject, Component, Injectable, Directive, EventEmitter, Output, Input, Host, Pipe, HostListener, forwardRef, ViewChild, HostBinding, ViewEncapsulation, NgModule, NO_ERRORS_SCHEMA, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import * as i1$1 from '@angular/material/dialog';
import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
import * as i1 from '@ngx-translate/core';
import { TranslateModule } from '@ngx-translate/core';
import * as i2 from '@angular/common';
import { CommonModule } from '@angular/common';
import * as i3 from '@angular/material/button';
import { MatButtonModule } from '@angular/material/button';
import * as i6 from '@angular/material/form-field';
import { MatFormFieldModule } from '@angular/material/form-field';
import * as i4 from '@angular/material/input';
import { MAT_INPUT_VALUE_ACCESSOR, MatInputModule } from '@angular/material/input';
import * as i8 from '@angular/flex-layout/flex';
import * as i3$1 from 'ngx-toastr';
import { BehaviorSubject, Subject, of, forkJoin, debounceTime, distinctUntilChanged, filter, tap, switchMap, throwError } from 'rxjs';
import * as i5 from '@angular/material/table';
import { MatTableDataSource, MatTableModule } from '@angular/material/table';
import * as i1$4 from '@angular/router';
import { RouterModule } from '@angular/router';
import * as i2$1 from 'ngx-filesaver';
import { catchError, map, finalize } from 'rxjs/operators';
import * as i1$5 from '@angular/material/paginator';
import { MatPaginatorIntl, MatPaginatorModule } from '@angular/material/paginator';
import * as i4$1 from '@angular/material/checkbox';
import { MatCheckboxModule } from '@angular/material/checkbox';
import * as i7 from '@angular/material/icon';
import { MatIconModule } from '@angular/material/icon';
import * as i8$1 from '@angular/material/tooltip';
import { MatTooltipModule } from '@angular/material/tooltip';
import * as i9 from '@angular/flex-layout/extended';
import * as i7$1 from '@angular/material/menu';
import { MatMenuModule } from '@angular/material/menu';
import * as i2$2 from '@angular/platform-browser';
import * as i5$1 from '@angular/cdk/text-field';
import * as i4$2 from '@angular/material/core';
import { NativeDateAdapter, DateAdapter, MAT_DATE_FORMATS, MatRippleModule, MatCommonModule } from '@angular/material/core';
import * as i5$2 from '@angular/material/datepicker';
import { MatDatepickerModule } from '@angular/material/datepicker';
import * as i10 from '@angular/cdk/scrolling';
import { CdkVirtualScrollViewport, ScrollingModule } from '@angular/cdk/scrolling';
import * as i9$1 from '@angular/material/select';
import { MatSelectModule } from '@angular/material/select';
import * as i3$2 from '@angular/material/autocomplete';
import { MatAutocompleteModule } from '@angular/material/autocomplete';
import * as i9$2 from '@angular/material/progress-spinner';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import * as i3$3 from '@angular/material/card';
import { MatCardModule } from '@angular/material/card';
import * as i3$4 from '@angular/material/progress-bar';
import { MatProgressBarModule } from '@angular/material/progress-bar';
import { NestedTreeControl, FlatTreeControl, CdkTreeModule, CdkTree, CdkTreeNode } from '@angular/cdk/tree';
import * as i6$1 from '@angular/material/tree';
import { MatTreeNestedDataSource, MatTreeFlattener, MatTreeFlatDataSource, MatTreeModule } from '@angular/material/tree';
import * as i4$3 from '@angular/material/radio';
import { MatRadioModule } from '@angular/material/radio';
import * as i6$2 from '@angular/material/divider';
import * as i4$4 from 'ngx-quill';
import { QuillModule } from 'ngx-quill';
import * as i1$6 from 'jsog-typescript';
import { OverlayModule } from '@angular/cdk/overlay';
import { A11yModule } from '@angular/cdk/a11y';
import { BidiModule } from '@angular/cdk/bidi';
import { ObserversModule } from '@angular/cdk/observers';
import { PortalModule } from '@angular/cdk/portal';
import { MatButtonToggleModule } from '@angular/material/button-toggle';
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
import { MatSliderModule } from '@angular/material/slider';
import { MatSidenavModule } from '@angular/material/sidenav';
import { MatListModule } from '@angular/material/list';
import { MatGridListModule } from '@angular/material/grid-list';
import { MatChipsModule } from '@angular/material/chips';
import { MatSnackBarModule } from '@angular/material/snack-bar';
import { MatTabsModule } from '@angular/material/tabs';
import { MatToolbarModule } from '@angular/material/toolbar';
import { MatSortModule } from '@angular/material/sort';
import { MatStepperModule } from '@angular/material/stepper';
import { ScrollingModule as ScrollingModule$1 } from '@angular/cdk-experimental/scrolling';
import { FlexLayoutModule } from '@angular/flex-layout';
class NavigatorModel {
displayName = '';
disabled = true;
iconName = '';
roleMenu = '';
route = '';
children = [];
isOnlyIcon = true;
expanded = false;
}
class ButtonClickEvent {
action;
object;
index;
constructor(action, object, index) {
this.action = action;
this.object = object;
this.index = index;
}
}
var IconTypeEnum;
(function (IconTypeEnum) {
IconTypeEnum["MATERIAL_ICON"] = "MATERIAL_ICON";
IconTypeEnum["FONT_AWESOME"] = "FONT_AWESOME";
})(IconTypeEnum || (IconTypeEnum = {}));
class ButtonModel {
columnDef = '';
color = 'warn';
icon = '';
iconType = IconTypeEnum.MATERIAL_ICON;
click = '';
isShowHeader;
title = '';
display;
disabled;
className;
header;
alignHeader;
}
class CheckboxModel {
id;
viewValue;
checked;
disabled;
constructor(id, viewValue, checked, disabled) {
this.id = id;
this.viewValue = viewValue;
this.checked = checked;
this.disabled = disabled;
}
}
var ColumnTypeEnum;
(function (ColumnTypeEnum) {
ColumnTypeEnum["VIEW"] = "VIEW";
ColumnTypeEnum["INPUT_COUNTER"] = "INPUT_COUNTER";
ColumnTypeEnum["DATE_PICKER"] = "DATE_PICKER";
ColumnTypeEnum["MULTI_SELECT_AUTOCOMPLETE"] = "MULTI_SELECT_AUTOCOMPLETE";
ColumnTypeEnum["CHECKBOX"] = "CHECKBOX";
ColumnTypeEnum["BASE64"] = "BASE64";
ColumnTypeEnum["IMG"] = "IMG";
ColumnTypeEnum["IMG_NO_SECURE"] = "IMG_NO_SECURE";
// HTML = 'HTML',
// INNER_TEXT = 'INNER_TEXT',
ColumnTypeEnum["BUTTON"] = "BUTTON";
ColumnTypeEnum["INPUT"] = "INPUT";
ColumnTypeEnum["LINK"] = "LINK";
ColumnTypeEnum["STYLE_CSS"] = "STYLE_CSS";
ColumnTypeEnum["LIVE_SEARCHING"] = "LIVE_SEARCHING";
})(ColumnTypeEnum || (ColumnTypeEnum = {}));
var AlignEnum;
(function (AlignEnum) {
AlignEnum["LEFT"] = "start";
AlignEnum["CENTER"] = "center";
AlignEnum["RIGHT"] = "end";
})(AlignEnum || (AlignEnum = {}));
class ColumnModel {
columnDef = '';
header;
// set default theo ly thuyet, phai gan lai
align = AlignEnum.LEFT;
alignHeader;
// phục vụ cho loại cột là hiển thị đường dẫn
link;
// Phục vụ cho style css
style;
className;
headerClassName;
columnType = ColumnTypeEnum.VIEW;
onCellValueChange;
onHeaderCellValueChange;
disabled;
optionValues;
display;
isShowHeader = false;
isNotShowHeaderCheckbox = false;
isRequired = false;
min;
max;
hasWordBreakStyle = false;
validate;
errorMessage;
isTree = false;
isMultipleSelect = false;
isDecimal = false;
isExpandOptionColumn;
footer;
footers = [];
button;
// Dùng cho cva-live-searching
displayKey;
mappingConfig = {};
searchFn;
title = (e) => `${e}`;
cell = (e) => `${e}`;
}
class BaseModel {
id;
checked = false;
invalid = false;
createdDate;
createdBy;
lastModifiedDate;
lastModifiedBy;
}
class MenuModel extends BaseModel {
clientId = null;
code = null;
url = null;
appType = null;
parentMenu = null;
constructor(form) {
super();
if (form instanceof FormGroup) {
this.id = form.get('id')?.value;
this.clientId = form.get('clientId')?.value;
this.code = form.get('code')?.value;
this.url = form.get('url')?.value;
this.appType = form.get('appType')?.value;
if (form.get('parentMenu')?.value) {
this.parentMenu = new MenuModel(form.get('parentMenu')?.value);
}
}
else {
this.id = form;
}
}
}
class OAuth2AuthenticationDto {
userAuthentication = null;
authorities = null;
name = null;
orgId = null;
orgCode = null;
orgName = null;
orgType = null;
orgForm = null;
orgPath = null;
orgIsApproveVo = null;
sapId = null;
voAuthentication = null;
}
class Authority {
authority = '';
}
class TablePagingResponseModel {
content = [];
page = {
size: null,
number: null,
totalElements: null,
totalPages: null,
};
}
class TablePagingRequestModel {
text = '';
pageSize = 0;
pageNumber = 0;
totalElements = 0;
}
class RoleModel extends BaseModel {
clientId = null;
roleName = null;
description = '';
permissions = [];
menus = [];
constructor(form) {
super();
if (!form) {
return;
}
if (form instanceof FormGroup) {
const formId = form.get('id');
if (formId) {
this.id = formId.value;
}
const formClientId = form.get('clientId');
if (formClientId) {
this.clientId = formClientId.value;
}
const formRoleName = form.get('roleName');
if (formRoleName) {
this.roleName = formRoleName.value;
}
const formDescription = form.get('description');
if (formDescription) {
this.description = formDescription.value;
}
}
else {
this.id = form;
}
}
}
class SelectModel {
value;
displayValue;
disabled;
rawData;
constructor(value, displayValue, disabled, rawData) {
this.value = value;
this.displayValue = displayValue;
this.disabled = disabled;
this.rawData = rawData;
}
}
class UIState {
moduleName = '';
formGroup = new FormGroup({});
}
var FileTypeEnum;
(function (FileTypeEnum) {
FileTypeEnum["DOCX"] = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
FileTypeEnum["JPG"] = "image/jpeg";
FileTypeEnum["PDF"] = "application/pdf";
FileTypeEnum["PNG"] = "image/png";
FileTypeEnum["RTF"] = "application/msword";
FileTypeEnum["TXT"] = "text/plain";
FileTypeEnum["XLSX"] = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
FileTypeEnum["XML"] = "text/xml";
FileTypeEnum["ZIP"] = "application/x-zip-compressed";
FileTypeEnum["DOC"] = "application/msword";
FileTypeEnum["XLS"] = "application/vnd.ms-excel";
})(FileTypeEnum || (FileTypeEnum = {}));
class UploadModel {
id;
name;
type;
binary;
previewValue;
constructor(name, binary, previewValue, type, id) {
this.name = name;
this.binary = binary;
this.previewValue = previewValue;
this.type = type;
this.id = id;
}
static init(url) {
const type = UploadModel.getFileType(url);
const name = UploadModel.getFileName(url);
return new UploadModel(name ? name : '', null, url, type);
}
static getFileType(url) {
const fileTypes = url ? url.split('.') : [];
const type = fileTypes.length > 0 ? fileTypes[fileTypes.length - 1] : '';
if (['png', 'jpg', 'jpeg', 'img'].includes(type?.toLowerCase())) {
return 'image/' + type;
}
else if ('pdf' === type?.toLowerCase()) {
return 'application/pdf';
}
return type;
}
static getFileName(url) {
let fileName = url ? url.split('/') : [];
return fileName.pop();
}
}
class BreadCrumbModel {
label;
url;
constructor(label, url) {
this.label = label;
this.url = url;
}
}
class FlatTreeModel {
rootData = [];
value = (node) => `${node}`;
display = (node) => `${node}`;
children = (node) => [];
}
class TableFooterModel {
columnDef = '';
title = (e) => `${e}`;
cell = (e) => `${e}`;
colspan = 1;
align = AlignEnum.LEFT;
className;
display; // default is false
}
class RangeDatePickerModel {
fromDate = '';
toDate = '';
constructor(fromDate, toDate) {
this.fromDate = fromDate ? fromDate : '';
this.toDate = toDate ? toDate : '';
}
isString(inputValue) {
return typeof inputValue === 'string' || inputValue instanceof String;
}
reset() {
this.toDate = '';
this.fromDate = '';
}
}
class FlatTreeConfigModel {
isDynamicConfig = false; /* bằng true khi muốn call liên tục hàm display và hàm disabled */
display = true;
disabled = false;
}
class FlatTreeNodeModel {
children = [];
value;
displayValue = '';
checked;
checkedDisplay;
filterChecked;
level = 0;
expandable;
isExpanded; // storage expanded status in selected tree
isFilterExpanded; // storage expanded status in choose tree
display = true;
_displayFuncInput;
disabled = false;
_disabledFuncInput;
}
var DialogTypeEnum;
(function (DialogTypeEnum) {
DialogTypeEnum["CONFIRM"] = "CONFIRM";
DialogTypeEnum["ERROR"] = "ERROR";
DialogTypeEnum["INPUT_CONFIRM"] = "INPUT_CONFIRM";
})(DialogTypeEnum || (DialogTypeEnum = {}));
class CustomDialogDataConfigModel {
type = DialogTypeEnum.CONFIRM;
maxLength;
msg;
msgDetail;
errorMsg;
btnOKString;
btnOKClass;
btnOK_IconClass;
btnCancelClass;
btnCancel_IconClass;
btnCancelString;
customClass;
hideIconButton;
}
class Principal {
username = null;
firstName = null;
middleName = null;
lastName = null;
fullName = null;
gender = null;
email = null;
phone = null;
voAuthentication = null;
orgId = null;
orgCode = null;
orgName = null;
orgType = null;
orgForm = null;
orgSapId = null;
orgPath = null;
orgIsApproveVo = null;
roles = [];
mustChangePassword = null;
}
class DialogImportFileConfigModel {
downloadTemplateFunc;
importFunc;
downloadErrorFile;
confirmMsgKey = '';
successMsgKey = '';
errorMsgKey = '';
}
class PermissionModel extends BaseModel {
clientId;
description;
id = null;
url;
}
var ActionTypeEnum;
(function (ActionTypeEnum) {
ActionTypeEnum["_ADD"] = "add";
ActionTypeEnum["_EDIT"] = "edit";
ActionTypeEnum["_VIEW"] = "view";
})(ActionTypeEnum || (ActionTypeEnum = {}));
var BaseStatusEnum;
(function (BaseStatusEnum) {
BaseStatusEnum["_"] = "base.status.all";
BaseStatusEnum["_DRAFT"] = "base.status.draft";
BaseStatusEnum["_APPROVED"] = "base.status.approved";
BaseStatusEnum["_REJECTED"] = "base.status.rejected";
})(BaseStatusEnum || (BaseStatusEnum = {}));
class BaseTableComponent {
activatedRoute;
authoritiesService;
me = null;
constructor(activatedRoute, authoritiesService) {
this.activatedRoute = activatedRoute;
this.authoritiesService = authoritiesService;
if (!this.authoritiesService.me && this.activatedRoute.snapshot.data) {
this.me = this.activatedRoute.snapshot.data['me'];
}
if (!!this.authoritiesService.me) {
this.me = this.authoritiesService.me;
}
if (!!this.me) {
this.authoritiesService.me = this.me;
this.authoritiesService.stateMe.next(this.me);
}
}
onRowButtonClick(event) {
const window = this;
if (window[event.action]) {
window[event.action](event.object, event.index);
}
}
_collectParams(searchForm, map) {
let params = new HttpParams();
for (const key of Object.keys(map)) {
const value = map[key];
if (value) {
const control = searchForm.get(value);
if (control) {
params = params.set(key, control.value ? control.value : '');
}
}
}
return params;
}
}
const InjectTokenNextSolutionsConfig = new InjectionToken('InjectTokenNextSolutionsConfig');
class CvaCustomDialogComponent {
translateService;
dialogRef;
injector;
data;
config;
get DialogTypeEnum() {
return DialogTypeEnum;
}
inputText = '';
errorInputText = '';
isError = false;
constructor(translateService, dialogRef, injector, ngControl, data) {
this.translateService = translateService;
this.dialogRef = dialogRef;
this.injector = injector;
this.data = data;
if (ngControl) {
// Hành động này thay cho provide: NG_VALUE_ACCESSOR và gắn ControlValueAccessor này vào parent FormControl
ngControl.valueAccessor = this;
}
this.config = injector.get(InjectTokenNextSolutionsConfig);
}
writeValue(obj) {
this.inputText = obj;
}
propagateChange = (_) => {
/*NON-EMPTY FOR COMPILE*/
};
registerOnChange(fn) {
this.propagateChange = fn;
}
registerOnTouched(fn) {
}
ngOnInit() {
}
onConfirm() {
if (this.data && this.data.type) {
if (this.data.type === DialogTypeEnum.INPUT_CONFIRM) {
this.isError = !this.inputText.trim();
if (this.isError) {
this.errorInputText = !!this.data?.errorMsg ? this.translateService.instant(this.data.errorMsg) : this.translateService.instant('common.required');
return;
}
this.dialogRef.close({ value: this.inputText });
}
else {
this.dialogRef.close({ value: 1 });
}
}
}
onCancel() {
this.dialogRef.close();
}
onChangeInput() {
this.isError = !this.inputText.trim();
if (this.isError) {
this.errorInputText = !!this.data?.errorMsg ? this.translateService.instant(this.data.errorMsg) : this.translateService.instant('common.required');
}
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: CvaCustomDialogComponent, deps: [{ token: i1.TranslateService }, { token: i1$1.MatDialogRef }, { token: i0.Injector }, { token: i1$2.NgControl, optional: true, self: true }, { token: MAT_DIALOG_DATA }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.5", type: CvaCustomDialogComponent, isStandalone: false, selector: "cva-custom-dialog", ngImport: i0, template: `
<div class="cva-custom-dialog dialog-content {{data.customClass}}" *ngIf="data"
style="padding-bottom: 0px !important;"
fxLayout="column">
<div class="img"
fxLayoutAlign="center center"
fxLayout
*ngIf="config && config.DIALOG_LOGO">
<img src="{{config.DIALOG_LOGO}}" alt="confirm-logo" />
</div>
<div class="content"
fxLayoutAlign="start stretch"
fxLayout="column">
<div class="text-msg">
{{ data && data.msg ? data.msg : '' }}
</div>
<div class="text-msg-detail" *ngIf="data && data.msgDetail">
{{ data.msgDetail }}
</div>
<!-- <div class="text-error" *ngIf="data.type === DialogTypeEnum.ERROR">-->
<!-- {{data && data.msg ? data.msg : ''}}-->
<!-- </div>-->
<!-- <div class="text-area" *ngIf="data.type === DialogTypeEnum.INPUT_CONFIRM"-->
<!-- fxLayoutAlign="center center"-->
<!-- fxLayout="column">-->
<!-- <label fxLayoutAlign="center center"-->
<!-- fxLayout>{{data && data.msg ? data.msg : ''}}</label>-->
<mat-form-field appearance="outline" class="input-confirm-dialog" fxFlex="100%"
fxLayout="column" *ngIf="data.type === DialogTypeEnum.INPUT_CONFIRM">
<textarea matInput [(ngModel)]="inputText" fxFlex="100%"
maxlength="{{(data && !!data.maxLength) ? data.maxLength : 524288}}"
(ngModelChange)="onChangeInput()"></textarea>
<span *ngIf="!!data && !!data.maxLength" class="input-suffix"
matSuffix>{{ (inputText?.length ? inputText.length : 0) + '/' + data.maxLength }}</span>
<mat-hint style="color: red" *ngIf="isError">{{ errorInputText }}</mat-hint>
</mat-form-field>
<!-- </div>-->
</div>
</div>
<hr class="display-hr-tag" *ngIf="data.type !== DialogTypeEnum.INPUT_CONFIRM">
<div class="buttonArea margin-top-10">
<button mat-button
class="{{data.btnCancelClass ? data.btnCancelClass : 'primary outline'}} btn-Cancel"
*ngIf="data.type !== DialogTypeEnum.ERROR"
(click)="onCancel()">
<i *ngIf="!data.hideIconButton"
class="{{data.btnCancel_IconClass ? data.btnCancel_IconClass : 'fa fa-times' }}"></i> {{ data && data.btnCancelString ? data.btnCancelString : ('common.Cancel' | translate) }}
</button>
<button mat-button
class="{{data.btnOKClass ? data.btnOKClass : 'primary'}} btn-OK"
(click)="onConfirm()">
<i *ngIf="!data.hideIconButton"
class="{{data.btnOK_IconClass ? data.btnOK_IconClass : 'fa fa-check'}}"></i> {{ data && data.btnOKString ? data.btnOKString : ('common.OK' | translate) }}
</button>
</div>
`, isInline: true, dependencies: [{ kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i3.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "component", type: i6.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i6.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "directive", type: i6.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "directive", type: i4.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "directive", type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { kind: "directive", type: i8.DefaultLayoutAlignDirective, selector: " [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]", inputs: ["fxLayoutAlign", "fxLayoutAlign.xs", "fxLayoutAlign.sm", "fxLayoutAlign.md", "fxLayoutAlign.lg", "fxLayoutAlign.xl", "fxLayoutAlign.lt-sm", "fxLayoutAlign.lt-md", "fxLayoutAlign.lt-lg", "fxLayoutAlign.lt-xl", "fxLayoutAlign.gt-xs", "fxLayoutAlign.gt-sm", "fxLayoutAlign.gt-md", "fxLayoutAlign.gt-lg"] }, { kind: "directive", type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { kind: "pipe", type: i1.TranslatePipe, name: "translate" }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: CvaCustomDialogComponent, decorators: [{
type: Component,
args: [{ selector: 'cva-custom-dialog', standalone: false, template: `
<div class="cva-custom-dialog dialog-content {{data.customClass}}" *ngIf="data"
style="padding-bottom: 0px !important;"
fxLayout="column">
<div class="img"
fxLayoutAlign="center center"
fxLayout
*ngIf="config && config.DIALOG_LOGO">
<img src="{{config.DIALOG_LOGO}}" alt="confirm-logo" />
</div>
<div class="content"
fxLayoutAlign="start stretch"
fxLayout="column">
<div class="text-msg">
{{ data && data.msg ? data.msg : '' }}
</div>
<div class="text-msg-detail" *ngIf="data && data.msgDetail">
{{ data.msgDetail }}
</div>
<!-- <div class="text-error" *ngIf="data.type === DialogTypeEnum.ERROR">-->
<!-- {{data && data.msg ? data.msg : ''}}-->
<!-- </div>-->
<!-- <div class="text-area" *ngIf="data.type === DialogTypeEnum.INPUT_CONFIRM"-->
<!-- fxLayoutAlign="center center"-->
<!-- fxLayout="column">-->
<!-- <label fxLayoutAlign="center center"-->
<!-- fxLayout>{{data && data.msg ? data.msg : ''}}</label>-->
<mat-form-field appearance="outline" class="input-confirm-dialog" fxFlex="100%"
fxLayout="column" *ngIf="data.type === DialogTypeEnum.INPUT_CONFIRM">
<textarea matInput [(ngModel)]="inputText" fxFlex="100%"
maxlength="{{(data && !!data.maxLength) ? data.maxLength : 524288}}"
(ngModelChange)="onChangeInput()"></textarea>
<span *ngIf="!!data && !!data.maxLength" class="input-suffix"
matSuffix>{{ (inputText?.length ? inputText.length : 0) + '/' + data.maxLength }}</span>
<mat-hint style="color: red" *ngIf="isError">{{ errorInputText }}</mat-hint>
</mat-form-field>
<!-- </div>-->
</div>
</div>
<hr class="display-hr-tag" *ngIf="data.type !== DialogTypeEnum.INPUT_CONFIRM">
<div class="buttonArea margin-top-10">
<button mat-button
class="{{data.btnCancelClass ? data.btnCancelClass : 'primary outline'}} btn-Cancel"
*ngIf="data.type !== DialogTypeEnum.ERROR"
(click)="onCancel()">
<i *ngIf="!data.hideIconButton"
class="{{data.btnCancel_IconClass ? data.btnCancel_IconClass : 'fa fa-times' }}"></i> {{ data && data.btnCancelString ? data.btnCancelString : ('common.Cancel' | translate) }}
</button>
<button mat-button
class="{{data.btnOKClass ? data.btnOKClass : 'primary'}} btn-OK"
(click)="onConfirm()">
<i *ngIf="!data.hideIconButton"
class="{{data.btnOK_IconClass ? data.btnOK_IconClass : 'fa fa-check'}}"></i> {{ data && data.btnOKString ? data.btnOKString : ('common.OK' | translate) }}
</button>
</div>
` }]
}], ctorParameters: () => [{ type: i1.TranslateService }, { type: i1$1.MatDialogRef }, { type: i0.Injector }, { type: i1$2.NgControl, decorators: [{
type: Self
}, {
type: Optional
}] }, { type: CustomDialogDataConfigModel, decorators: [{
type: Inject,
args: [MAT_DIALOG_DATA]
}] }] });
class UtilsService {
dialog;
transService;
toastr;
constructor(dialog, transService, toastr) {
this.dialog = dialog;
this.transService = transService;
this.toastr = toastr;
}
static getEnumValue(o, value) {
return o['_' + value]; // No type safety here unfrotunately
}
static calcPosition(e, results, paging) {
return (paging ? ((paging.pageNumber - 1) * paging.pageSize) : 0) + (results.data.indexOf(e) + 1);
}
static reduceEntityAttributeForFormControl(formGroup, e, dateRangeConfigList) {
return Object.keys(formGroup.controls).reduce(reduceEntityAttributeForFormControlByControlName, {});
function reduceEntityAttributeForFormControlByControlName(formControl, ctrlName) {
if (e) {
let includesOfDateRangeConfig = false;
if (dateRangeConfigList) {
for (const dateRangeConfig of dateRangeConfigList) {
if (dateRangeConfig
&& [dateRangeConfig.dateRangeControlName,
dateRangeConfig.fromDateControlName, dateRangeConfig.toDateControlName].includes(ctrlName)) {
includesOfDateRangeConfig = true;
switch (ctrlName) {
case dateRangeConfig.dateRangeControlName:
formControl[ctrlName] = {
fromDate: e[dateRangeConfig.fromDateControlName] ? e[dateRangeConfig.fromDateControlName] : null,
toDate: e[dateRangeConfig.toDateControlName] ? e[dateRangeConfig.toDateControlName] : null,
};
break;
case dateRangeConfig.fromDateControlName:
formControl[ctrlName] = e[ctrlName];
if (formControl[dateRangeConfig.dateRangeControlName]
&& typeof (formControl[dateRangeConfig.dateRangeControlName]) === 'object') {
formControl[dateRangeConfig.dateRangeControlName].fromDate = e[ctrlName];
}
break;
case dateRangeConfig.toDateControlName:
formControl[ctrlName] = e[ctrlName];
if (formControl[dateRangeConfig.dateRangeControlName]
&& typeof (formControl[dateRangeConfig.dateRangeControlName]) === 'object') {
formControl[dateRangeConfig.dateRangeControlName].toDate = e[ctrlName];
}
break;
default:
break;
}
}
}
}
if (!includesOfDateRangeConfig) {
if (typeof (e[ctrlName]) === 'boolean') {
formControl[ctrlName] = e[ctrlName] ? '1' : '0';
}
else if (e[ctrlName] instanceof Array) {
formControl[ctrlName] = e[ctrlName];
}
else if (typeof (e[ctrlName]) === 'object') {
formControl[ctrlName] = e[ctrlName]
? (e[ctrlName].id
? e[ctrlName].id
: (e[ctrlName].code ? e[ctrlName].code : ''))
: null;
}
else {
formControl[ctrlName] = (e[ctrlName] != null && e[ctrlName] != undefined) ? e[ctrlName] : '';
}
}
}
else {
formControl[ctrlName] = '';
}
return formControl;
}
}
static cloneAbstractControl(control) {
let newControl;
if (control instanceof FormGroup) {
const formGroup = new FormGroup({}, control.validator, control.asyncValidator);
const controls = control.controls;
if (controls) {
Object.keys(controls).forEach(key => {
const tempControl = UtilsService.cloneAbstractControl(controls[key]);
if (tempControl) {
formGroup.addControl(key, tempControl);
}
});
}
newControl = formGroup;
}
else if (control instanceof FormArray) {
const formArray = new FormArray([], control.validator, control.asyncValidator);
const controls = control.controls;
if (controls) {
controls.forEach((formControl) => {
const tempControl = UtilsService.cloneAbstractControl(formControl);
if (tempControl) {
formArray.push(tempControl);
}
});
}
newControl = formArray;
}
else if (control instanceof FormControl || this.isNgControl(control)) {
newControl = new FormControl(control.value, control.validator, control.asyncValidator);
}
else {
console.error('Error: unexpected formControl value', control);
}
if (control.disabled && newControl)
newControl.disable({ emitEvent: false });
return newControl;
}
static isNgControl(control) {
return control && 'control' in control;
}
static convertTreeDataToAutocompleteData(treeFields, symbol, hasChildFn, nodes, prefixDisplayValue) {
let result = [];
if (treeFields) {
for (const node of nodes) {
const value = treeFields.value(node).toString();
const displayValue = prefixDisplayValue ? prefixDisplayValue + symbol + treeFields.display(node) : treeFields.display(node);
const hasChild = hasChildFn(0, node);
if (hasChild) {
const childen = treeFields.children(node);
result.push(...this.convertTreeDataToAutocompleteData(treeFields, symbol, hasChildFn, childen, displayValue));
}
else {
result.push(new SelectModel(value, displayValue, hasChild, node));
}
}
}
return result;
}
strFormat(str, replacement) {
let a = this.transService.instant(str);
if (replacement === null || replacement === undefined || replacement.length === 0) {
return a;
}
replacement.forEach((value, index) => {
a = a.replace('{' + index + '}', this.transService.instant(value));
});
return a;
}
onSuccessFunc = (onSuccessMessage) => {
if (onSuccessMessage) {
const msg = this.transService.instant(onSuccessMessage);
this.toastr.toastrConfig.positionClass = 'toast-bottom-right';
this.toastr.success(msg);
}
};
showWarningToarst(msgKey, replacement) {
const msg = this.strFormat(msgKey, replacement);
this.toastr.toastrConfig.positionClass = 'toast-bottom-right';
this.toastr.warning(msg);
}
showErrorToarst(msgKey, replacement) {
const msg = this.strFormat(msgKey, replacement);
this.toastr.toastrConfig.positionClass = 'toast-bottom-right';
this.toastr.error(msg);
}
showError = (err) => {
let errLocale = '';
if (err !== undefined && err !== null) {
errLocale = this.transService.instant(err);
}
this.dialog.open(CvaCustomDialogComponent, {
width: '500px',
data: {
msg: `${errLocale}`,
type: DialogTypeEnum.ERROR,
},
});
};
execute3(apiCall, onSuccessFunc, onSuccessMessage, onErrorFunc) {
if (!apiCall) {
if (onSuccessFunc) {
onSuccessFunc(null);
}
return;
}
apiCall.subscribe((data) => {
if (onSuccessFunc) {
if (onSuccessMessage) {
onSuccessFunc(data, onSuccessMessage);
}
else {
onSuccessFunc(data);
}
}
else {
this.onSuccessFunc(onSuccessMessage);
}
}, (error1) => {
if (error1 !== '401') {
if (!!onErrorFunc) {
onErrorFunc(error1);
}
else {
this.showError(error1);
}
}
});
}
execute(apiCall, onSuccessFunc, onSuccessMessage, confirmMsgTitle, confirmMsgTitleParamsFormat = [], confirmMsgDetail = '', confirmMsgDetailParamsFormat = [], confirmDialogConfig = undefined, confirmDialogButtonOk = 'common.OK', confirmDialogButtonCancel = 'common.Cancel') {
if (confirmMsgTitle !== undefined && confirmMsgTitle !== null && confirmMsgTitle !== '') {
this.showConfirmDialog(confirmMsgTitle, confirmMsgTitleParamsFormat, confirmMsgDetail, confirmMsgDetailParamsFormat, confirmDialogConfig, confirmDialogButtonOk, confirmDialogButtonCancel)
.afterClosed().subscribe(result => {
if (result && result.value) {
this.execute3(apiCall, onSuccessFunc, onSuccessMessage);
}
});
}
else {
this.execute3(apiCall, onSuccessFunc, onSuccessMessage);
}
}
executeWithErrorHandle(method, onSuccessFunc, onSuccessMessage, confirmMsgTitle, confirmMsgParamsFormat = [], confirmMsgDetail = '', confirmMsgDetailParamsFormat = [], onErrorFunc, dialogConfig, confirmDialogButtonOk = 'common.OK', confirmDialogButtonCancel = 'common.Cancel') {
if (confirmMsgTitle !== undefined && confirmMsgTitle !== null && confirmMsgTitle !== '') {
this.showConfirmDialog(confirmMsgTitle, confirmMsgParamsFormat, confirmMsgDetail, confirmMsgDetailParamsFormat, dialogConfig, confirmDialogButtonOk, confirmDialogButtonCancel)
.afterClosed().subscribe((result) => {
if (result && result.value) {
this.execute3(method(), onSuccessFunc, onSuccessMessage, onErrorFunc);
}
});
}
else {
this.execute3(method(), onSuccessFunc, onSuccessMessage, onErrorFunc);
}
}
showConfirmDialog(strTitle, replacementTitle, strDetailMsg = '', replacementDetail = [], confirmDialogConfig = undefined, strOkText = 'common.OK', strCancelTex = 'common.Cancel', strCustomClass) {
const msgTitle = this.strFormat(strTitle, replacementTitle);
const msgDetail = !!strDetailMsg ? this.strFormat(strDetailMsg, replacementDetail) : '';
const strOk = this.transService.instant(strOkText);
const strCancel = this.transService.instant(strCancelTex);
const re = /\./gi;
const customClass = (strCustomClass ? strCustomClass : strTitle).replace(re, '-');
return this.dialog.open(CvaCustomDialogComponent, confirmDialogConfig ? confirmDialogConfig : {
width: '500px',
data: {
customClass: customClass,
msg: msgTitle,
msgDetail: msgDetail,
type: DialogTypeEnum.CONFIRM,
btnOKString: strOk,
btnCanceString: strCancel,
},
});
}
showConfirmInputDialog(str1, replacement, confirmInputDialogConfig = undefined, strOkText = 'common.OK', strCancelTex = 'common.Cancel', strCustomClass) {
const str = this.strFormat(str1, replacement);
const strOk = this.transService.instant(strOkText);
const strCancel = this.transService.instant(strCancelTex);
const re = /\./gi;
const customClass = (strCustomClass ? strCustomClass : str1).replace(re, '-');
return this.dialog.open(CvaCustomDialogComponent, confirmInputDialogConfig ? confirmInputDialogConfig : {
width: '500px',
data: {
customClass: customClass,
msg: str,
type: DialogTypeEnum.INPUT_CONFIRM,
btnOKString: strOk,
btnCancelString: strCancel,
},
});
}
getEnumValueTranslated(o, value) {
const key = o['_' + value]; // No type safety here unfrotunately
return this.transService.instant(key);
}
toBlobJon(obj) {
return new Blob([JSON.stringify(obj)], {
type: 'application/json',
});
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: UtilsService, deps: [{ token: i1$1.MatDialog }, { token: i1.TranslateService }, { token: i3$1.ToastrService }], target: i0.ɵɵFactoryTarget.Injectable });
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: UtilsService, providedIn: 'root' });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: UtilsService, decorators: [{
type: Injectable,
args: [{ providedIn: 'root' }]
}], ctorParameters: () => [{ type: i1$1.MatDialog }, { type: i1.TranslateService }, { type: i3$1.ToastrService }] });
class ApiService {
http;
fileSaver;
injector;
config;
constructor(http, fileSaver, injector) {
this.http = http;
this.fileSaver = fileSaver;
this.injector = injector;
this.config = injector.get(InjectTokenNextSolutionsConfig);
}
getFullUrl(url) {
return this.config.BASE_URL + url;
}
get(nativeUrl, params, baseUrl) {
return this.http.get(baseUrl ? (baseUrl + nativeUrl) : this.getFullUrl(nativeUrl), { params });
}
getJSON(file) {
return this.http.get(file);
}
getBlob(nativeUrl, params, baseUrl) {
const url = baseUrl ? (baseUrl + nativeUrl) : this.getFullUrl(nativeUrl);
return this.http.get(url, {
responseType: 'blob', // Đặt responseType thành 'blob'
});
}
post(nativeUrl, obj, options, baseUrl) {
return this.http.post(baseUrl ? (baseUrl + nativeUrl) : this.getFullUrl(nativeUrl), obj, options ? {
headers: options.headers,
params: options.params,
} : {});
}
postBlob(nativeUrl, obj, options, baseUrl) {
return this.http.post(baseUrl ? (baseUrl + nativeUrl) : this.getFullUrl(nativeUrl), obj, {
headers: options.headers,
params: options.params,
observe: 'response',
responseType: 'blob',
});
}
patch(nativeUrl, obj, options, baseUrl) {
return this.http.patch(baseUrl ? (baseUrl + nativeUrl) : this.getFullUrl(nativeUrl), obj, options ? { headers: options.headers, params: options.params } : {});
}
put(nativeUrl, obj, options, baseUrl) {
return this.http.put(baseUrl ? (baseUrl + nativeUrl) : this.getFullUrl(nativeUrl), obj, options ? { headers: options.headers, params: options.params } : {});
}
delete(nativeUrl, options, baseUrl) {
return this.http.delete(baseUrl ? (baseUrl + nativeUrl) : this.getFullUrl(nativeUrl), options ? {
headers: options.headers,
params: options.params,
} : {});
}
saveFile(nativeUrl, obj, options, baseUrl, onErrorFunc) {
this.http.post(baseUrl ? (baseUrl + nativeUrl) : this.getFullUrl(nativeUrl), obj, {
headers: options.headers,
params: options.params,
observe: 'response',
responseType: 'blob',
}).subscribe((l) => {
let filename = '';
const disposition = l.headers.get('Content-Disposition');
if (disposition && disposition.indexOf('attachment') !== -1) {
const filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
const matches = filenameRegex.exec(disposition);
if (matches != null && matches[1]) {
filename = matches[1].replace(/['"]/g, '');
}
}
const blobData = l.body;
const contentType = l.headers.get('Content-Type');
if (blobData && contentType) {
this.fileSaver.save(blobData, filename, contentType);
}
}, (err) => {
if (onErrorFunc) {
onErrorFunc(err);
}
});
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: ApiService, deps: [{ token: i1$3.HttpClient }, { token: i2$1.FileSaverService }, { token: i0.Injector }], target: i0.ɵɵFactoryTarget.Injectable });
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: ApiService, providedIn: 'root' });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: ApiService, decorators: [{
type: Injectable,
args: [{ providedIn: 'root' }]
}], ctorParameters: () => [{ type: i1$3.HttpClient }, { type: i2$1.FileSaverService }, { type: i0.Injector }] });
class FormStateService {
subject = new BehaviorSubject(new Map());
uiState$ = this.subject.asObservable();
setMapState(mapState) {
this.subject.next(mapState);
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: FormStateService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: FormStateService, providedIn: 'root' });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: FormStateService, decorators: [{
type: Injectable,
args: [{ providedIn: 'root' }]
}] });
class AuthoritiesService {
me = null;
stateMe = new BehaviorSubject(new OAuth2AuthenticationDto());
me$ = this.stateMe.asObservable();
hasAuthorities(authorities) {
if (!authorities) {
return false;
}
let checkAuthority = false;
for (const authority of authorities) {
checkAuthority = checkAuthority || this.hasAuthority(authority.toLowerCase());
if (checkAuthority) {
break;
}
}
return checkAuthority;
}
hasAuthority(authority) {
if (!authority || !this.me || !this.me.authorities) {
return false;
}
return this.me.authorities.map(x => x.authority.toString().toLowerCase()).includes(authority.toLowerCase());
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: AuthoritiesService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: AuthoritiesService, providedIn: 'root' });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: AuthoritiesService, decorators: [{
type: Injectable,
args: [{ providedIn: 'root' }]
}] });
class BaseSearchComponent extends BaseTableComponent {
router;
apiService;
utilsService;
formStateService;
translateService;
injector;
activatedRoute;
authoritiesService;
formGroup;
isAdvancedSearch = false;
searchForm;
paging;
results = new MatTableDataSource([]);
columns = [];
config;
moduleName = '';
unsubscribe$ = new Subject();
isResetPaging = true;
constructor(router, apiService, utilsService, formStateService, translateService, injector, activatedRoute, authoritiesService, formGroup) {
super(activatedRoute, authoritiesService);
this.router = router;
this.apiService = apiService;
this.utilsService = utilsService;
this.formStateService = formStateService;
this.translateService = translateService;
this.injector = injector;
this.activatedRoute = activatedRoute;
this.authoritiesService = authoritiesService;
this.formGroup = formGroup;
this.searchForm = this.formGroup;
this.config = injector.get(InjectTokenNextSolutionsConfig);
this.paging = new TablePagingRequestModel();
this.paging.pageSize = this.config.PAGE_SIZE;
this.paging.pageNumber = 1;
this.paging.totalElements = 0;
}
ngOnInit() {
this.formStateService.uiState$
.subscribe((mapState) => {
if (mapState && mapState.has(this.moduleName)) {
const stateFormGroup = mapState.get(this.moduleName);
if (stateFormGroup) {
const formGroup = UtilsService.cloneAbstractControl(stateFormGroup);
if (formGroup) {
if (!this.searchForm) {
this.searchForm = formGroup;
}
else {
const formControls = formGroup.controls;
Object.keys(formControls).forEach(key => {
const abstractControl = this.searchForm.get(key);
if (abstractControl) {
abstractControl.setValue(formControls[key].value);
}
});
}
}
}
}
});
}
ngAfterViewInit() {
Object.keys(this.searchForm.controls).forEach(key => {
const abstractControl = this.searchForm.get(key);
if (abstractControl) {
abstractControl.valueChanges.subscribe(value => {
this.isResetPaging = true;
});
}
});
}
ngOnDestroy() {
let isOK = false;
this.formStateService.uiState$.subscribe((mapState) => {
if (!isOK) {
isOK = true;
mapState.set(this.moduleName, this.searchForm);
this.formStateService.setMapState(mapState);
this.unsubscribe$.next();
this.unsubscribe$.complete();
}
});
}
onSubmit() {
this.isResetPaging = true;
this.search();
}
search() {
// Form extends will be override custom by business
}
afterSearch = (data) => {
// Form extends will be override custom by business
};
_fillData(nativeUrl, params, baseUrl) {
params = this.updateHttpParams(params);
this.apiService.get(nativeUrl, params, baseUrl).subscribe(this.afterFillData);
}
_fillDataByPostMethod(nativeUrl, obj, options, baseUrl) {
options.params = this.updateHttpParams(options.params);
this.apiService.post(nativeUrl, obj, options, baseUrl).subscribe(this.afterFillData);
}
pagingChange(event) {
if (this.paging) {
this.paging = event;
this.search();
}
else {
this.paging = event;
}
}
onClick(event) {
// Form extends will be override custom by business
}
onSuccessFunc = (data, onSuccessMessage) => {
this.utilsService.onSuccessFunc(onSuccessMessage ? onSuccessMessage : 'common.default.success');
this.search();
};
resetSearchFormValue() {
if (!this.searchForm) {
return;
}
for (const ctrName in this.searchForm.controls) {
this.searchForm.controls[ctrName].setValue('');
}
}
toggleAdvancedSearch() {
this.isAdvancedSearch = !this.isAdvancedSearch;
}
params2Object(params) {
const result = {};
params = this.removeEmptyParams(params);
params.keys().forEach(k => {
const value = params.get(k);
if (value && value.indexOf(',') >= 0) {
result[k] = value?.split(',');
}
else {
result[k] = value;
}
});
return result;
}
afterFillData = (data) => {
this.isResetPaging = false;
if (data.content && data.content.length > 0) {
this.columns.forEach((column) => {
column.isShowHeader = false;
});
}
this.afterSearch(data);
this.results = new MatTableDataSource(data.content);
this.paging = new TablePagingRequestModel();
this.paging.pageSize = data.page.size ? data.page.size : 0;
this.paging.pageNumber = (data.page.number ? data.page.number : 0) + 1;
this.paging.totalElements = data.page.totalElements ? data.page.totalElements : 0;
};
removeEmptyParams(params) {
params.keys().forEach(key => {
const value = params.get(key) ? params.get(key) + '' : '';
if (value) {
params = params.set(key, value.trim());
}
});
const emptyValuesKey = params.keys().filter(key => !params.get(key));
emptyValuesKey.forEach(key => {
params = params.delete(key);
});
return params;
}
updateHttpParams(params) {
params = this.removeEmptyParams(params);
if (!params.keys().includes('pageNumber')) {
params = params.append('pageNumber', this.isResetPaging ? '1' : (this.paging ? this.paging.pageNumber.toString() : '1'))
.append('pageSize', this.paging ? this.paging.pageSize.toString() : this.config.PAGE_SIZE.toString());
}
return params;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: BaseSearchComponent, deps: [{ token: i1$4.Router }, { token: ApiService }, { token: UtilsService }, { token: FormStateService }, { token: i1.TranslateService }, { token: i0.Injector }, { token: i1$4.ActivatedRoute }, { token: AuthoritiesService }, { token: i1$2.FormGroup }], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.1.5", type: BaseSearchComponent, isStandalone: false, selector: "BaseSearchComponent", usesInheritance: true, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: BaseSearchComponent, decorators: [{
type: Directive,
args: [{
selector: 'BaseSearchComponent',
standalone: false,
}]
}], ctorParameters: () => [{ type: i1$4.Router }, { type: ApiService }, { type: UtilsService }, { type: FormStateService }, { type: i1.TranslateService }, { type: i0.Injector }, { type: i1$4.ActivatedRoute }, { type: AuthoritiesService }, { type: i1$2.FormGroup }] });
class BaseAddEditComponent extends BaseTableComponent {
activatedRoute;
location;
translateService;
utilsService;
authoritiesService;
addEditForm = new FormGroup({});
isEdit;
id;
isView = false;
constructor(activatedRoute, location, translateService, utilsService, authoritiesService) {
super(activatedRoute, authoritiesService);
this.activatedRoute = activatedRoute;
this.location = location;
this.translateService = translateService;
this.utilsService = utilsService;
this.authoritiesService = authoritiesService;
this.isEdit = false;
}
ngOnInit() {
this.id = this.activatedRoute.snapshot.paramMap.get('id');
if (this.id) {
this.isEdit = true;
}
this.isView = this.activatedRoute.routeConfig?.data?.actionType === ActionTypeEnum._VIEW;
}
back() {
this.location.back();
}
onSuccessFunc = (data, onSuccessMessage) => {
this.utilsService.onSuccessFunc(onSuccessMessage ? onSuccessMessage : 'common.default.success');
setTimeout(() => {
this.back();
}, 1500);
};
hasAuthority() {
return false;
}
getPosition(e, arr) {
return !!arr && arr.length > 0 ? (arr.indexOf(e) + 1).toString() : '';
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: BaseAddEditComponent, deps: [{ token: i1$4.ActivatedRoute }, { token: i2.Location }, { token: i1.TranslateService }, { token: UtilsService }, { token: AuthoritiesService }], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.1.5", type: BaseAddEditComponent, isStandalone: false, selector: "BaseAddEditComponent", usesInheritance: true, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: BaseAddEditComponent, decorators: [{
type: Directive,
args: [{
selector: 'BaseAddEditComponent',
standalone: false,
}]
}], ctorParameters: () => [{ type: i1$4.ActivatedRoute }, { type: i2.Location }, { type: i1.TranslateService }, { type: UtilsService }, { type: AuthoritiesService }] });
class MultiTranslateHttpLoader {
http;
resources;
constructor(http, resources) {
this.http = http;
this.resources = resources;
}
getTranslation(lang) {
const requests = this.resources.map(resource => {
const path = resource.prefix + lang + resource.suffix;
return this.http.get(path).pipe(catchError(res => {
console.error('Something went wrong for the following translation file:', path);
console.error(res.message);
return of({});
}));
});
return forkJoin(requests).pipe(map(responses => {
if (!responses.length)
return {};
const target = {};
for (const index in responses) {
Object.assign(target, responses[index]);
}
return target;
}));
}
}
class MultiLanguageTablePaginator extends MatPaginatorIntl {
translateService;
constructor(translateService) {
super();
this.translateService = translateService;
this.translateService.onLangChange.subscribe((e) => {
this.getAndInitTranslations();
});
this.getAndInitTranslations();
}
range = '';
getAndInitTranslations() {
this.translateService.get('MatPaginator.itemsPerPageLabel').subscribe((res) => {
this.itemsPerPageLabel = res;
});
this.translateService.get('MatPaginator.nextPageLabel').subscribe((res) => {
this.nextPageLabel = res;
});
this.translateService.get('MatPaginator.previousPageLabel').subscribe((res) => {
this.previousPageLabel = res;
});
this.translateService.get('MatPaginator.range').subscribe((res) => {
this.range = ' ' + res + ' ';
});
this.changes.next();
}
getRangeLabel = (page, pageSize, length) => {
// use style-paginator directive
return '';
// if (length === 0 || pageSize === 0) {
// return '0' + this.range + length;
// }
// length = Math.max(length, 0);
// const startIndex = page * pageSize;
// const endIndex = startIndex < length ?
// Math.min(startIndex + pageSize, length) :
// startIndex + pageSize;
// return startIndex + 1 + ' - ' + endIndex + this.range + length;
};
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: MultiLanguageTablePaginator, deps: [{ token: i1.TranslateService }], target: i0.ɵɵFactoryTarget.Injectable });
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: MultiLanguageTablePaginator, providedIn: 'root' });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: MultiLanguageTablePaginator, decorators: [{
type: Injectable,
args: [{
providedIn: 'root',
}]
}], ctorParameters: () => [{ type: i1.TranslateService }] });
class TableService {
static DEFAULT_NO_IMAGE_AVAILABLE = 'data:image/png;base64, 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';
static displayHeaderName(column, moduleName) {
if (typeof (column.header) === 'string') {
return moduleName + '.table.header.' + column.header;
}
return column.header ? column.header(column) : '';
}
static onDisplayButtonHeaderCell(buttons, button, header, index) {
if (typeof (button.header) === 'object' && !!button.header) {
return (button.isShowHeader ? button.isShowHeader : false) ||
((button.header && button.header.display) ? button.header.display(header) : false);
}
if (typeof (button.header) === 'string') {
return !(!!buttons[index - 1] && typeof (buttons[index - 1].header) === 'string');
}
return false;
}
static getColumnType(col, row) {
if (!col.columnType) {
return ColumnTypeEnum.VIEW;
}
return (typeof (col.columnType) === 'function' ? col.columnType(row) : col.columnType);
}
static getHeaderButtonColspan(buttons, data) {
if (!buttons) {
return 0;
}
let displayCell = false;
return buttons.reduce((colspan, button) => {
displayCell = data.some(row => TableService.onDisplayButtonCell(button, row));
return colspan + (displayCell ? 1 : 0);
}, 0);
}
static onDisplayButtonCell(button, cell) {
button.isShowHeader = button.isShowHeader || (button.display ? button.display(cell) : false);
return button.display ? button.display(cell) : false;
}
static onDisplayCell(column, cell) {
if (column.display) {
column.isShowHeader = column.isShowHeader || column.display(cell);
}
else {
column.isShowHeader = true;
}
return column.isShowHeader;
}
static alignCellContent(column) {
return column.align ? column.align : AlignEnum.LEFT;
}
static getColspan(footer, data) {
return typeof (footer.colspan) === 'function' ? footer.colspan(data) : footer.colspan;
}
static getColumnClassName(col, data = null) {
return !!col && !!col.className ? (typeof (col.className) === 'function' ? col.className(data) : col.className) : '';
}
static getColumnHeaderClassName(col) {
return !!col && !!col.headerClassName ? (typeof (col.headerClassName) === 'function' ? col.headerClassName() : col.headerClassName) : '';
}
static getIconType(button) {
return button.iconType ? button.iconType : IconTypeEnum.MATERIAL_ICON;
}
static onErrorImgEvent(img, noImageConfigBase64) {
img.onerror = null;
img.src = noImageConfigBase64 ? noImageConfigBase64 : TableService.DEFAULT_NO_IMAGE_AVAILABLE;
}
static isButtonHeader(button) {
return !!button.header && typeof (button.header) === 'object';
}
static getButtonHeader(button) {
return this.isButtonHeader(button) ? button.header : null;
}
static getButtonHeaderString(button) {
return !this.isButtonHeader(button) ? button.header : null;
}
}
class LoaderService {
isLoading = new BehaviorSubject(false);
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: LoaderService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: LoaderService, providedIn: 'root' });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: LoaderService, decorators: [{
type: Injectable,
args: [{ providedIn: 'root' }]
}] });
class ValidatorService {
static invalid(control) {
return !!control && control.dirty ? control.invalid : false;
}
static getErrorMessage(control, errorMessages) {
if (!control) {
return '';
}
const { errors } = control;
const messages = errors ? Object.keys(errors).map(key => {
const fn = errorMessages.has(key) ? errorMessages.get(key) : null;
return fn ? fn(errors) : 'common.error.' + key;
}) : [];
return messages && messages.length > 0 ? messages[0] : '';
}
static getErrorMessageV1(control, errorMessages) {
if (!control) {
return '';
}
const { errors } = control;
if (!errors) {
return {};
}
let errKey = Object.keys(errors)[0];
const fn = errorMessages && errorMessages.has(errKey) ? errorMessages.get(errKey) : null;
const msg = fn ? fn(errors) : 'common.error.' + errKey;
// const messages: string[] = errors ? Object.keys(errors).map(key => {
// const fn = errorMessages.has(key) ? errorMessages.get(key) : null;
// errKey = key;
// return fn ? fn(errors) : 'common.error.' + key;
// }) : [];
return errors && msg ? { msg, params: errors[errKey] } : {};
}
static generateNsMultiSelectValidators(conditions) {
const validationFns = [];
const validation = (control) => {
const value = control.value;
if (ValidatorService.getRequiredDynamic(conditions.required) && (value === undefined || value === null || value === ''
|| (!!conditions.multiple && value.length === 0))) {
return { required: true };
}
return null;
};
validationFns.push(validation);
return validationFns;
}
static generateNsInputValidators(conditions) {
const validationFns = [];
if (conditions.required) {
validationFns.push(Validators.required);
}
if (conditions.minLength) {
validationFns.push(Validators.minLength(conditions.minLength));
}
if (conditions.maxLength) {
validationFns.push(Validators.maxLength(conditions.maxLength));
}
if (conditions.pattern) {
validationFns.push(Validators.pattern(conditions.pattern));
}
return validationFns;
}
static generateNsAutocompleteValidators(conditions) {
const validationFns = [];
if (conditions.required) {
validationFns.push(Validators.required);
}
return validationFns;
}
static getMinMaxDynamic(minOrMax) {
return minOrMax !== null ? typeof (minOrMax) === 'function' ? minOrMax() : minOrMax : null;
}
static generateNsCounterInputValidators(conditions) {
const validationFns = [];
validationFns.push(Validators.pattern(conditions.isDecimal ? '^[^-]?[0-9]+[.]?[0-9]*$' : '^[0-9]*$'));
if (conditions.required) {
validationFns.push(Validators.required);
}
if (conditions.min != undefined && conditions.min != null) {
const validationMin = (control) => {
return ValidatorService.customMinValueNsCounterInput(control.value, ValidatorService.getMinMaxDynamic(conditions.min));
};
validationFns.push(validationMin);
}
if (conditions.max != undefined && conditions.max != null) {
const validationMax = (control) => {
return ValidatorService.customMaxValueNsCounterInput(control.value, ValidatorService.getMinMaxDynamic(conditions.max));
};
validationFns.push(validationMax);
}
return validationFns;
}
static generateNsDatePickerValidators(conditions) {
const validationFns = [];
if (conditions.required) {
validationFns.push(Validators.required);
}
// if (conditions.min) {
// validationFns.push(new NsValidator({minDate: conditions.min}).customMinDateValidator());
// }
// if (conditions.max) {
// validationFns.push(new NsValidator({maxDate: conditions.max}).customMaxDateValidator());
// }
return validationFns;
}
static getRequiredDynamic(isRequired) {
return isRequired ? typeof (isRequired) === 'boolean' ? isRequired : isRequired() : false;
}
static generateNsDateRangePickerValidators(conditions) {
const validationFns = [];
// if (NsValidator.getRequiredDynamic(conditions.requiredFromDate)
// || NsValidator.getRequiredDynamic(conditions.requiredToDate)) {
const validation = (control) => {
const range = control.value;
if (!range?.fromDate && ValidatorService.getRequiredDynamic(conditions.requiredFromDate)) {
return { requiredFromDate: true };
}
if (!range?.toDate && ValidatorService.getRequiredDynamic(conditions.requiredToDate)) {
return { requiredToDate: true };
}
return null;
};
validationFns.push(validation);
// }
return validationFns;
}
// customMinDateValidator(): ValidatorFn {
// return this.customMinDateValidatorControl;
// }
static customMinDateValidatorControl(value, minDate) {
if (!minDate || !value) {
return null;
}
let date = value instanceof Date ? value : new Date(value.replace(' ', 'T'));
if (date < new Date(minDate.getFullYear(), minDate.getMonth(), minDate.getDate(), 0, 0, 0)) {
return { min: { valid: false, minValue: minDate, actual: date } };
}
return null;
}
// customMaxDateValidator(): ValidatorFn {
// return this.customMaxDateValidatorControl;
// }
static customMaxDateValidatorControl(value, maxDate) {
if (!maxDate || !value) {
return null;
}
let date = value instanceof Date ? value : new Date(value.replace(' ', 'T').replace('Z', ''));
if (date > new Date(maxDate.getFullYear(), maxDate.getMonth(), maxDate.getDate(), 0, 0, 0)) {
return { max: { valid: false, maxValue: maxDate, actual: date } };
}
return null;
}
static getRequired(column) {
return column.isRequired ? typeof (column.isRequired) === 'boolean' ? column.isRequired : column.isRequired() : false;
}
static getIsDecimal(column) {
return column.isDecimal ? typeof (column.isDecimal) === 'boolean' ? column.isDecimal : column.isDecimal() : false;
}
static customMinValueNsCounterInput(value, min) {
if (!isNaN(Number(value)) && min !== null && value < min) {
return { min: { min: min, actual: value } };
}
return null;
}
static customMaxValueNsCounterInput(value, max) {
if (!isNaN(Number(value)) && max !== null && value > max) {
return { max: { max: max, actual: value } };
}
return null;
}
static generateNsSmartTableValidators(conditions) {
const validator = (control) => {
let errors = null;
if (control) {
const controlValueLength = control.value ? control.value.length : 0;
if (conditions.minRow > controlValueLength) {
return { minRow: { valid: false, min: conditions.minRow, actual: controlValueLength } };
}
if (conditions.maxRow < controlValueLength) {
return { maxRow: { valid: false, max: conditions.maxRow, actual: controlValueLength } };
}
if (!control.value) {
return null;
}
control.value.forEach((row) => {
if (errors || !conditions.columns) {
return;
}
conditions.columns.forEach((column) => {
if (errors) {
return;
}
const tempControl = new FormControl();
tempControl.setValue(row[column.columnDef]);
if (TableService.getColumnType(column, row) === ColumnTypeEnum.MULTI_SELECT_AUTOCOMPLETE) {
if (ValidatorService.getRequired(column)) {
tempControl.setValidators(Validators.required);
}
}
else if (TableService.getColumnType(column, row) === ColumnTypeEnum.INPUT_COUNTER) {
tempControl.setValidators(ValidatorService.generateNsCounterInputValidators({
required: ValidatorService.getRequired(column),
min: null,
max: null,
isDecimal: ValidatorService.getIsDecimal(column),
}));
}
else if (TableService.getColumnType(column, row) === ColumnTypeEnum.DATE_PICKER) {
tempControl.setValidators(ValidatorService.generateNsDatePickerValidators({
required: ValidatorService.getRequired(column),
min: null,
max: null,
}));
}
else if (TableService.getColumnType(column, row) === ColumnTypeEnum.INPUT) {
tempControl.setValidators(ValidatorService.generateNsInputValidators({
required: ValidatorService.getRequired(column),
maxLength: column.max ? column.max(row) : undefined,
minLength: column.min ? column.min(row) : undefined,
pattern: undefined,
}));
}
tempControl.updateValueAndValidity();
if (TableService.getColumnType(column, row) === ColumnTypeEnum.DATE_PICKER) {
const errorsArr = [];
if (tempControl.errors) {
errorsArr.push(tempControl.errors);
}
if (ValidatorService.customMinDateValidatorControl(tempControl.value, column.min ? column.min(row) : null)) {
errorsArr.push(ValidatorService.customMinDateValidatorControl(tempControl.value, column.min ? column.min(row) : null));
}
if (ValidatorService.customMaxDateValidatorControl(tempControl.value, column.max ? column.max(row) : null)) {
errorsArr.push(ValidatorService.customMaxDateValidatorControl(tempControl.value, column.max ? column.max(row) : null));
}
if (errorsArr.length > 0) {
tempControl.setErrors(errorsArr);
}
}
if (TableService.getColumnType(column, row) === ColumnTypeEnum.INPUT_COUNTER) {
const errorsArr = [];
if (tempControl.errors) {
errorsArr.push(tempControl.errors);
}
if (ValidatorService.customMinValueNsCounterInput(tempControl.value, column.min ? column.min(row) : null)) {
errorsArr.push(ValidatorService.customMinValueNsCounterInput(tempControl.value, column.min ? column.min(row) : null));
}
if (ValidatorService.customMaxValueNsCounterInput(tempControl.value, column.max ? column.max(row) : null)) {
errorsArr.push(ValidatorService.customMaxValueNsCounterInput(tempControl.value, column.max ? column.max(row) : null));
}
if (errorsArr.length > 0) {
tempControl.setErrors(errorsArr);
}
}
tempControl.markAllAsTouched();
errors = tempControl.errors;
});
});
}
return errors;
};
return validator;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: ValidatorService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: ValidatorService, providedIn: 'root' });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: ValidatorService, decorators: [{
type: Injectable,
args: [{ providedIn: 'root' }]
}] });
class CvaCounterInputComponent {
injector;
label = '';
placeholder = '';
suffixText = '';
hint = '';
value = 0;
disabled = false;
required = false;
errorMessages = new Map();
min = null;
max = null;
error;
isDecimal = false;
isLabelOutside = false;
isFloatLabel = true;
/* percent label outside css */
percentOfLabelOutside = 25;
alignNumber = AlignEnum.RIGHT;
// Chỉ bằng false khi trong NsSmartTable thôi nhé @@
isFormControl = true;
onChange = new EventEmitter();
onEnter = new EventEmitter();
// Cái này là để gắn khi nó là FormControl trong 1 FormGroup
formControl;
constructor(injector, ngControl) {
this.injector = injector;
if (ngControl) {
// ngControl là parent FormControl
// Hành động này thay cho provide: NG_VALUE_ACCESSOR và gắn ControlValueAccessor này vào parent FormControl
ngControl.valueAccessor = this;
}
}
get NsValidator() {
return ValidatorService;
}
get counterValue() {
return this.value;
}
set counterValue(val) {
this.writeValue(val);
}
ngOnChanges(changes) {
if ('value' in changes) {
this.value = changes.value.currentValue;
this.writeValue(this.value);
}
}
ngOnInit() {
this.callValidator();
}
getMinNumber() {
return typeof (this.min) === 'function' ? this.min() : this.min;
}
getMaxNumber() {
return typeof (this.max) === 'function' ? this.max() : this.max;
}
callValidator() {
const ngControl = this.injector.get(NgControl);
// Nếu parent FormControl khởi tạo xong và formControl chưa có giá trị lưu
if (ngControl && !this.formControl) {
// Nếu là NsSmartTable thì phải tự new FormControl còn không thì cứ hóng parent FormControl về ^^
if (this.isFormControl) {
this.formControl = ngControl.control ? ngControl.control : undefined;
}
else {
this.formControl = new FormControl();
}
// Hành động này gắn validator vào this.formControl
// - Nếu this.formControl là parent FormControl thì sẽ show error lên FormGroup
// - Nếu this.formControl là new FormControl thì sẽ quét QueryList để check {errors}
if (this.formControl) {
this.formControl.setValidators(ValidatorService.generateNsCounterInputValidators({
required: this.required,
min: this.min,
max: this.max,
isDecimal: this.isDecimal,
}));
}
}
if (this.formControl) {
// Nếu this.formControl thuộc NsSmartTable thì setValue lại
if (!this.isFormControl) {
this.formControl.setValue(this.value);
}
// Nếu là parent FormControl rồi thì kệ
this.formControl.updateValueAndValidity();
if (!this.formControl.errors) {
const minErr = ValidatorService.customMinValueNsCounterInput(this.value, this.getMinNumber());
if (minErr) {
this.formControl.setErrors(minErr);
}
const maxErr = ValidatorService.customMaxValueNsCounterInput(this.value, this.getMaxNumber());
if (maxErr) {
this.formControl.setErrors(maxErr);
}
this.formControl.markAllAsTouched();
if (!this.isFormControl) {
this.formControl.markAsDirty();
}
}
}
}
writeValue(value) {
if (value !== undefined) {
this.value = value;
this.propagateChange(this.value);
this.callValidator();
this.onChange.emit(this.value);
}
}
propagateChange = (_) => {
/*NON-EMPTY FOR COMPILE*/
};
registerOnChange(fn) {
this.propagateChange = fn;
}
registerOnTouched() {
/*NON-EMPTY FOR COMPILE*/
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: CvaCounterInputComponent, deps: [{ token: i0.Injector }, { token: i1$2.NgControl, optional: true, self: true }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.5", type: CvaCounterInputComponent, isStandalone: false, selector: "cva-counter-input", inputs: { label: "label", placeholder: "placeholder", suffixText: "suffixText", hint: "hint", value: "value", disabled: "disabled", required: "required", errorMessages: "errorMessages", min: "min", max: "max", error: "error", isDecimal: "isDecimal", isLabelOutside: "isLabelOutside", isFloatLabel: "isFloatLabel", percentOfLabelOutside: "percentOfLabelOutside", alignNumber: "alignNumber", isFormControl: "isFormControl" }, outputs: { onChange: "onChange", onEnter: "onEnter" }, usesOnChanges: true, ngImport: i0, template: `
<!-- css labelOutside trong base.theme-->
<div class="cva-counter-input"
[ngClass]="{'labelOutside': !!isLabelOutside, 'float_label': !!isFloatLabel && !isLabelOutside}"
fxLayout="row" fxLayout.lt-sm="row wrap">
<mat-label *ngIf="isLabelOutside" class="label_width"
fxLayout="column" fxFlex="auto" fxFlex.lt-md="100%">
<div class="label">
<div>
{{ (label ? label : placeholder) | translate }}<span
class="required-label-outside">{{ !!required ? '*' : '' }}</span>
</div>
</div>
</mat-label>
<mat-form-field appearance="outline" [floatLabel]="!!isFloatLabel ? 'always' : 'auto'"
[hideRequiredMarker]="!isFloatLabel"
fxLayout="column" fxFlex="auto" fxFlex.lt-md="100%">
<mat-label *ngIf="!isLabelOutside && !!isFloatLabel">{{ (label ? label : placeholder) | translate }}</mat-label>
<div class="input-area">
<input matInput type="number" [(ngModel)]="counterValue" #nsCounterInput="ngModel"
style="text-align:{{alignNumber}}"
[disabled]="disabled" [required]="required"
(keydown.enter)="onEnter.emit()"
[placeholder]="placeholder|translate"
autocomplete="off"
pattern="{{isDecimal ? '^[^-]?[0-9]+[.]?[0-9]*$' : '^[0-9]*$'}}" min="{{min}}" max="{{max}}" />
<span *ngIf="!!suffixText" class="input-suffix"
matSuffix>{{ suffixText }}</span>
</div>
<mat-hint *ngIf="!NsValidator.invalid(formControl)">
{{ hint | translate }}
</mat-hint>
<mat-hint style="color: red" *ngIf="NsValidator.invalid(formControl)">
{{ NsValidator.getErrorMessage(formControl, errorMessages) | translate }}
</mat-hint>
</mat-form-field>
</div>
`, isInline: true, dependencies: [{ kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$2.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { kind: "directive", type: i1$2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "directive", type: i1$2.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i6.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i6.MatLabel, selector: "mat-label" }, { kind: "directive", type: i6.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "directive", type: i6.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "directive", type: i4.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "directive", type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { kind: "directive", type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { kind: "directive", type: i9.DefaultClassDirective, selector: " [ngClass], [ngClass.xs], [ngClass.sm], [ngClass.md], [ngClass.lg], [ngClass.xl], [ngClass.lt-sm], [ngClass.lt-md], [ngClass.lt-lg], [ngClass.lt-xl], [ngClass.gt-xs], [ngClass.gt-sm], [ngClass.gt-md], [ngClass.gt-lg]", inputs: ["ngClass", "ngClass.xs", "ngClass.sm", "ngClass.md", "ngClass.lg", "ngClass.xl", "ngClass.lt-sm", "ngClass.lt-md", "ngClass.lt-lg", "ngClass.lt-xl", "ngClass.gt-xs", "ngClass.gt-sm", "ngClass.gt-md", "ngClass.gt-lg"] }, { kind: "pipe", type: i1.TranslatePipe, name: "translate" }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: CvaCounterInputComponent, decorators: [{
type: Component,
args: [{
selector: 'cva-counter-input',
standalone: false,
template: `
<!-- css labelOutside trong base.theme-->
<div class="cva-counter-input"
[ngClass]="{'labelOutside': !!isLabelOutside, 'float_label': !!isFloatLabel && !isLabelOutside}"
fxLayout="row" fxLayout.lt-sm="row wrap">
<mat-label *ngIf="isLabelOutside" class="label_width"
fxLayout="column" fxFlex="auto" fxFlex.lt-md="100%">
<div class="label">
<div>
{{ (label ? label : placeholder) | translate }}<span
class="required-label-outside">{{ !!required ? '*' : '' }}</span>
</div>
</div>
</mat-label>
<mat-form-field appearance="outline" [floatLabel]="!!isFloatLabel ? 'always' : 'auto'"
[hideRequiredMarker]="!isFloatLabel"
fxLayout="column" fxFlex="auto" fxFlex.lt-md="100%">
<mat-label *ngIf="!isLabelOutside && !!isFloatLabel">{{ (label ? label : placeholder) | translate }}</mat-label>
<div class="input-area">
<input matInput type="number" [(ngModel)]="counterValue" #nsCounterInput="ngModel"
style="text-align:{{alignNumber}}"
[disabled]="disabled" [required]="required"
(keydown.enter)="onEnter.emit()"
[placeholder]="placeholder|translate"
autocomplete="off"
pattern="{{isDecimal ? '^[^-]?[0-9]+[.]?[0-9]*$' : '^[0-9]*$'}}" min="{{min}}" max="{{max}}" />
<span *ngIf="!!suffixText" class="input-suffix"
matSuffix>{{ suffixText }}</span>
</div>
<mat-hint *ngIf="!NsValidator.invalid(formControl)">
{{ hint | translate }}
</mat-hint>
<mat-hint style="color: red" *ngIf="NsValidator.invalid(formControl)">
{{ NsValidator.getErrorMessage(formControl, errorMessages) | translate }}
</mat-hint>
</mat-form-field>
</div>
`,
}]
}], ctorParameters: () => [{ type: i0.Injector }, { type: i1$2.NgControl, decorators: [{
type: Self
}, {
type: Optional
}] }], propDecorators: { label: [{
type: Input
}], placeholder: [{
type: Input
}], suffixText: [{
type: Input
}], hint: [{
type: Input
}], value: [{
type: Input
}], disabled: [{
type: Input
}], required: [{
type: Input
}], errorMessages: [{
type: Input
}], min: [{
type: Input
}], max: [{
type: Input
}], error: [{
type: Input
}], isDecimal: [{
type: Input
}], isLabelOutside: [{
type: Input
}], isFloatLabel: [{
type: Input
}], percentOfLabelOutside: [{
type: Input
}], alignNumber: [{
type: Input
}], isFormControl: [{
type: Input
}], onChange: [{
type: Output
}], onEnter: [{
type: Output
}] } });
class StylePaginatorDirective {
config;
matPag;
vr;
ren;
_currentPage = 1;
_pageGapTxt = '...';
_rangeStart;
_rangeEnd;
_buttons = [];
_showTotalPages = 5;
get showTotalPages() {
return this._showTotalPages;
}
set showTotalPages(value) {
this._showTotalPages = value % 2 == 0 ? value + 1 : value;
}
$paging;
get paging() {
return this.$paging;
}
set paging(paging) {
if (paging) {
this.$paging = paging;
// pageIndex = pageNumber -1
this.switchPage(paging.pageNumber - 1, false);
}
}
pagingChangeEvent = new EventEmitter(); // PageEvent
constructor(config, matPag, vr, ren) {
this.config = config;
this.matPag = matPag;
this.vr = vr;
this.ren = ren;
//Sub to rerender buttons when next page and last page is used or choose pageSize
this.matPag.page.subscribe((pageEvent) => {
if (this.paging) {
this.paging.pageSize = pageEvent.pageSize;
}
this.switchPage(pageEvent.pageIndex, true);
});
}
buildPageNumbers() {
const actionContainer = this.vr.element.nativeElement.querySelector('div.mat-paginator-range-actions');
const nextPageNode = this.vr.element.nativeElement.querySelector('button.mat-paginator-navigation-next');
// remove buttons before creating new ones
if (this._buttons.length > 0) {
this._buttons.forEach(button => {
this.ren.removeChild(actionContainer, button);
});
//Empty state array
this._buttons.length = 0;
}
//initialize next page and last page buttons
if (this._buttons.length == 0) {
let nodeArray = this.vr.element.nativeElement?.childNodes[0]?.childNodes[0]
?.childNodes[2]?.childNodes;
if (nodeArray) {
setTimeout(() => {
for (let i = 0; i < nodeArray.length; i++) {
if (nodeArray[i].nodeName === 'BUTTON') {
if (nodeArray[i].disabled) {
this.ren.setStyle(nodeArray[i], 'background-color', 'rgba(190, 130, 130, 1)');
this.ren.setStyle(nodeArray[i], 'color', 'white');
this.ren.setStyle(nodeArray[i], 'margin', '.5%');
}
else {
this.ren.setStyle(nodeArray[i], 'background-color', 'rgba(255, 0, 0, 1)');
this.ren.setStyle(nodeArray[i], 'color', 'white');
this.ren.setStyle(nodeArray[i], 'margin', '.6%');
}
}
}
});
}
}
let dots = false;
if ((!!this._rangeStart || this._rangeStart === 0) && (!!this._rangeEnd || this._rangeEnd === 0)) {
for (let i = 0; i < this.matPag.getNumberOfPages(); i = i + 1) {
if ((i < this._showTotalPages &&
this._currentPage < this._showTotalPages &&
i > this._rangeStart) ||
(i >= this._rangeStart && i <= this._rangeEnd)) {
this.ren.insertBefore(actionContainer, this.createButton(i, this.matPag.pageIndex), nextPageNode);
}
else {
if (i > this._rangeEnd && !dots) {
// if (!isNaN(i)) {
// this.ren.insertBefore(
// actionContainer,
// this.createButton(this._pageGapTxt, this.matPag.pageIndex),
// nextPageNode
// );
// dots = true;
// }
}
}
}
}
}
createButton(i, pageIndex) {
const linkBtn = this.ren.createElement('mat-button');
this.ren.addClass(linkBtn, 'mat-mini-fab');
this.ren.setStyle(linkBtn, 'margin', '1%');
const pagingTxt = isNaN(i) ? this._pageGapTxt : +(i + 1);
const text = this.ren.createText(pagingTxt + '');
this.ren.addClass(linkBtn, 'mat-custom-page');
switch (i) {
case pageIndex:
this.ren.setAttribute(linkBtn, 'disabled', 'disabled');
break;
case this._pageGapTxt:
// this.ren.listen(linkBtn, "click", () => {
// this.switchPage(this._currentPage + this._showTotalPages);
// });
break;
default:
this.ren.listen(linkBtn, 'click', () => {
this.switchPage(i, true);
});
break;
}
this.ren.appendChild(linkBtn, text);
//Add button to private array for state
this._buttons.push(linkBtn);
return linkBtn;
}
initPageRange() {
this._rangeStart = this._currentPage - this._showTotalPages / 2;
this._rangeEnd = this._currentPage + this._showTotalPages / 2;
this.buildPageNumbers();
}
switchPage(i, isEvent) {
this._currentPage = i;
this.matPag.pageIndex = i;
if (isEvent) {
this.pagingChangeEvent.emit({
pageIndex: i,
pageSize: this.paging ? this.paging.pageSize : this.config.PAGE_SIZE,
});
}
this.initPageRange();
}
ngAfterViewInit() {
this.initPageRange();
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: StylePaginatorDirective, deps: [{ token: InjectTokenNextSolutionsConfig }, { token: i1$5.MatPaginator, host: true, optional: true, self: true }, { token: i0.ViewContainerRef }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.1.5", type: StylePaginatorDirective, isStandalone: false, selector: "[style-paginator]", inputs: { showTotalPages: "showTotalPages", paging: "paging" }, outputs: { pagingChangeEvent: "pagingChangeEvent" }, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: StylePaginatorDirective, decorators: [{
type: Directive,
args: [{
selector: '[style-paginator]',
standalone: false,
}]
}], ctorParameters: () => [{ type: undefined, decorators: [{
type: Inject,
args: [InjectTokenNextSolutionsConfig]
}] }, { type: i1$5.MatPaginator, decorators: [{
type: Host
}, {
type: Self
}, {
type: Optional
}] }, { type: i0.ViewContainerRef }, { type: i0.Renderer2 }], propDecorators: { showTotalPages: [{
type: Input
}], paging: [{
type: Input
}], pagingChangeEvent: [{
type: Output
}] } });
class CvaHeaderExpandButtonComponent {
expandHeaderButton;
columns = [];
moduleName = '';
onChange = new EventEmitter();
expandDisplayCols = {};
constructor() {
}
get ColumnTypes() {
return ColumnTypeEnum;
}
get IconTypes() {
return IconTypeEnum;
}
get TableService() {
return TableService;
}
ngOnInit() {
this.columns.forEach(col => {
this.expandDisplayCols[col.columnDef] = !(col.isExpandOptionColumn ? col.isExpandOptionColumn() : false);
col.isExpandOptionColumn = () => !this.expandDisplayCols[col.columnDef];
});
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: CvaHeaderExpandButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.5", type: CvaHeaderExpandButtonComponent, isStandalone: false, selector: "cva-header-expand-button", inputs: { expandHeaderButton: "expandHeaderButton", columns: "columns", moduleName: "moduleName" }, outputs: { onChange: "onChange" }, ngImport: i0, template: `
<button mat-icon-button
class="expand-column-header-button"
color="{{expandHeaderButton?.color}}"
[matMenuTriggerFor]="menu"
matTooltip="{{((expandHeaderButton && expandHeaderButton.title) ? expandHeaderButton.title : '') | translate}}"
>
<mat-icon *ngIf="expandHeaderButton && TableService.getIconType(expandHeaderButton)===IconTypes.MATERIAL_ICON">
{{ expandHeaderButton?.icon }}
</mat-icon>
<i *ngIf="expandHeaderButton && TableService.getIconType(expandHeaderButton) === IconTypes.FONT_AWESOME"
class="{{expandHeaderButton?.icon}}"></i>
</button>
<mat-menu class="menu-expand-column" #menu="matMenu">
<div class="header-menu-expand" fxLayout fxLayoutAlign="space-between center">
<mat-label>{{ 'common.expand.menu.header.label' | translate }}</mat-label>
<button mat-flat-button>{{ 'common.label.done' | translate }}</button>
</div>
<div class="choose-area" (click)="$event.stopPropagation()">
<div mat-menu-item *ngFor="let col of columns">
<ng-container *ngIf="col.columnType!==ColumnTypes.CHECKBOX">
<mat-checkbox style="width: 100%"
[(ngModel)]="expandDisplayCols[col.columnDef]"
[value]="col.columnDef"
(change)="this.onChange.emit(this.expandDisplayCols)">
{{ (moduleName + '.table.header.' + col.header) | translate }}
</mat-checkbox>
</ng-container>
</div>
</div>
</mat-menu>
`, isInline: true, dependencies: [{ kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i3.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "component", type: i3.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "component", type: i4$1.MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "directive", type: i6.MatLabel, selector: "mat-label" }, { kind: "component", type: i7.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i7$1.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i7$1.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i7$1.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "directive", type: i8$1.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "directive", type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { kind: "directive", type: i8.DefaultLayoutAlignDirective, selector: " [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]", inputs: ["fxLayoutAlign", "fxLayoutAlign.xs", "fxLayoutAlign.sm", "fxLayoutAlign.md", "fxLayoutAlign.lg", "fxLayoutAlign.xl", "fxLayoutAlign.lt-sm", "fxLayoutAlign.lt-md", "fxLayoutAlign.lt-lg", "fxLayoutAlign.lt-xl", "fxLayoutAlign.gt-xs", "fxLayoutAlign.gt-sm", "fxLayoutAlign.gt-md", "fxLayoutAlign.gt-lg"] }, { kind: "pipe", type: i1.TranslatePipe, name: "translate" }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: CvaHeaderExpandButtonComponent, decorators: [{
type: Component,
args: [{
selector: 'cva-header-expand-button',
standalone: false,
template: `
<button mat-icon-button
class="expand-column-header-button"
color="{{expandHeaderButton?.color}}"
[matMenuTriggerFor]="menu"
matTooltip="{{((expandHeaderButton && expandHeaderButton.title) ? expandHeaderButton.title : '') | translate}}"
>
<mat-icon *ngIf="expandHeaderButton && TableService.getIconType(expandHeaderButton)===IconTypes.MATERIAL_ICON">
{{ expandHeaderButton?.icon }}
</mat-icon>
<i *ngIf="expandHeaderButton && TableService.getIconType(expandHeaderButton) === IconTypes.FONT_AWESOME"
class="{{expandHeaderButton?.icon}}"></i>
</button>
<mat-menu class="menu-expand-column" #menu="matMenu">
<div class="header-menu-expand" fxLayout fxLayoutAlign="space-between center">
<mat-label>{{ 'common.expand.menu.header.label' | translate }}</mat-label>
<button mat-flat-button>{{ 'common.label.done' | translate }}</button>
</div>
<div class="choose-area" (click)="$event.stopPropagation()">
<div mat-menu-item *ngFor="let col of columns">
<ng-container *ngIf="col.columnType!==ColumnTypes.CHECKBOX">
<mat-checkbox style="width: 100%"
[(ngModel)]="expandDisplayCols[col.columnDef]"
[value]="col.columnDef"
(change)="this.onChange.emit(this.expandDisplayCols)">
{{ (moduleName + '.table.header.' + col.header) | translate }}
</mat-checkbox>
</ng-container>
</div>
</div>
</mat-menu>
`,
}]
}], ctorParameters: () => [], propDecorators: { expandHeaderButton: [{
type: Input
}], columns: [{
type: Input
}], moduleName: [{
type: Input
}], onChange: [{
type: Output
}] } });
class SecureImgPipe {
http;
sanitizer;
constructor(http, sanitizer) {
this.http = http;
this.sanitizer = sanitizer;
}
transform(url) {
return this.http
.get(url, {
headers: new HttpHeaders().set('is_image', 'true'),
responseType: 'blob',
})
.pipe(map(value => this.sanitizer.bypassSecurityTrustUrl(URL.createObjectURL(value))));
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: SecureImgPipe, deps: [{ token: i1$3.HttpClient }, { token: i2$2.DomSanitizer }], target: i0.ɵɵFactoryTarget.Pipe });
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.1.5", ngImport: i0, type: SecureImgPipe, isStandalone: false, name: "secure" });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: SecureImgPipe, decorators: [{
type: Pipe,
args: [{
name: 'secure',
standalone: false,
}]
}], ctorParameters: () => [{ type: i1$3.HttpClient }, { type: i2$2.DomSanitizer }] });
class CvaTableComponent {
config;
cdRef;
loaderService;
moduleName = '';
varPaging;
results = new MatTableDataSource([]);
columns = [];
buttons = [];
showTotalPages = 5;
expandHeaderButton;
pageSizeOptions;
pagingChange = new EventEmitter(true);
clickAction = new EventEmitter();
onRowClickAction = new EventEmitter();
onChangeDisplayColumn = new EventEmitter();
selectAllChecked = false;
goToPageNumber = 1;
errorMsg = new Map()
.set('min', () => '')
.set('max', () => '')
.set('pattern', () => '')
.set('required', () => '');
// display status object column in table
expandDisplayCols = {};
buttonColspan = 0;
constructor(config,
/*public domSanitizer: DomSanitizer,*/
cdRef, loaderService) {
this.config = config;
this.cdRef = cdRef;
this.loaderService = loaderService;
this.pageSizeOptions = this.config.PAGE_SIZE_OPTIONS;
this.varPaging = new TablePagingRequestModel();
this.varPaging.pageSize = this.config.PAGE_SIZE;
this.varPaging.pageNumber = 1;
this.varPaging.totalElements = 0;
}
set paging(value) {
if (value) {
this.varPaging = value;
}
}
get displayedColumns() {
let columnsDef = this.columns.map(c => c.columnDef);
if (this.buttons) {
columnsDef = columnsDef.concat(this.buttons.map(b => b.columnDef));
}
// if (!!this.expandHeaderButton) {
// columnsDef = columnsDef.concat(this.expandHeaderButton.columnDef);
// }
return columnsDef;
}
get ColumnTypes() {
return ColumnTypeEnum;
}
get IconTypes() {
return IconTypeEnum;
}
get AlignEnum() {
return AlignEnum;
}
get TableService() {
return TableService;
}
isExpandColumn(col) {
return !!col.isExpandOptionColumn ? col.isExpandOptionColumn() : false;
}
getPage(pageable) {
this.varPaging.pageNumber = pageable.pageIndex + 1;
this.varPaging.pageSize = pageable.pageSize;
this.pagingChange.emit(this.varPaging);
this.toggleSelect(null, null);
this.goToPageNumber = this.varPaging.pageNumber;
}
onClick(action, result) {
const buttonClickEvent = new ButtonClickEvent(action, result);
this.clickAction.emit(buttonClickEvent);
}
ngOnInit() {
if (!this.varPaging) {
this.varPaging = new TablePagingRequestModel();
this.varPaging.pageSize = this.config.PAGE_SIZE;
this.varPaging.pageNumber = 1;
this.varPaging.totalElements = 0;
this.pagingChange.emit(this.varPaging);
}
// setup binding object with column
this.columns.forEach(col => {
this.expandDisplayCols[col.columnDef] = !(col.isExpandOptionColumn ? col.isExpandOptionColumn() : false);
col.isExpandOptionColumn = () => !this.expandDisplayCols[col.columnDef];
});
}
onRowClick(result, index) {
const buttonClickModel = new ButtonClickEvent('onRowClick', result, index);
this.onRowClickAction.emit(buttonClickModel);
}
onDisplayHeaderCell(column) {
return (column.isShowHeader ? column.isShowHeader : !this.hasData()) && !this.isExpandColumn(column);
}
onDisplayCell(column, cell) {
return TableService.onDisplayCell(column, cell) && !this.isExpandColumn(column);
}
toggleSelectAll(val, col) {
this.results.data.forEach(v => {
v.checked = val.checked;
});
if (col.onHeaderCellValueChange) {
col.onHeaderCellValueChange(val.checked);
}
}
toggleSelect(val, result, column) {
let count = 0;
this.results.data.forEach(v => {
if (v.checked) {
count++;
}
});
this.selectAllChecked = count === this.results.data.length;
if (column && column.onCellValueChange) {
column.onCellValueChange(result);
}
}
ngAfterViewChecked() {
this.getHeaderButtonColspan();
this.cdRef.detectChanges();
}
hasData() {
return this.results && this.results.data && this.results.data.length > 0;
}
getTotalPage() {
if (!this.varPaging) {
return 0;
}
return (this.varPaging.totalElements % this.varPaging.pageSize) === 0
? Math.floor(this.varPaging.totalElements / this.varPaging.pageSize)
: Math.floor((this.varPaging.totalElements / this.varPaging.pageSize) + 1);
}
goToPage() {
if (this.goToPageNumber) {
this.getPage({ pageIndex: this.goToPageNumber - 1, pageSize: this.varPaging.pageSize });
}
}
getHeaderButtonColspan() {
this.buttonColspan = TableService.getHeaderButtonColspan(this.buttons, this.results.data);
return this.buttonColspan;
}
onChangeGoToPageNumber($event) {
if ($event === null || Number.isNaN($event) || !Number.isSafeInteger($event)) {
this.goToPageNumber = 1;
return;
}
if (this.goToPageNumber > this.getTotalPage()) {
this.goToPageNumber = this.getTotalPage();
}
const item = window.document.querySelector('.go-to-page cva-counter-input .mat-mdc-form-field-infix input');
if (item && item.closest) {
const itemClosest = item.closest('.mat-mdc-form-field-infix');
if (itemClosest) {
itemClosest.style.width = ($event.toString().length * 15 + 20) + 'px';
}
}
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: CvaTableComponent, deps: [{ token: InjectTokenNextSolutionsConfig }, { token: i0.ChangeDetectorRef }, { token: LoaderService }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.5", type: CvaTableComponent, isStandalone: false, selector: "cva-table", inputs: { moduleName: "moduleName", results: "results", columns: "columns", buttons: "buttons", showTotalPages: "showTotalPages", expandHeaderButton: "expandHeaderButton", paging: "paging" }, outputs: { pagingChange: "pagingChange", clickAction: "clickAction", onRowClickAction: "onRowClickAction", onChangeDisplayColumn: "onChangeDisplayColumn" }, providers: [
{ provide: MatPaginatorIntl, useClass: MultiLanguageTablePaginator },
], ngImport: i0, template: `
<div class="table-responsive">
<ng-container *ngIf="!!expandHeaderButton">
<cva-header-expand-button [moduleName]="moduleName" [expandHeaderButton]="expandHeaderButton"
[columns]="columns" (onChange)="this.onChangeDisplayColumn.emit($event)">
</cva-header-expand-button>
</ng-container>
<table mat-table #table [dataSource]="results" class="mat-elevation-z8 cva-table">
<ng-container *ngFor="let column of columns" matColumnDef="{{column.columnDef}}">
<ng-container *matHeaderCellDef>
<th mat-header-cell [ngClass]="TableService.getColumnHeaderClassName(column)"
*ngIf="onDisplayHeaderCell(column)"
[ngSwitch]="TableService.getColumnType(column, null)">
<div fxLayout="row" *ngSwitchDefault
class="viewData"
[ngClass]="{'break-word-style-view': column.hasWordBreakStyle}"
[fxLayoutAlign]="column.alignHeader ? column.alignHeader : TableService.alignCellContent(column)">
{{ TableService.displayHeaderName(column, moduleName) | translate }}
</div>
<mat-checkbox *ngSwitchCase="ColumnTypes.CHECKBOX"
color="primary" class="box-select-all" [(ngModel)]="selectAllChecked"
(change)="toggleSelectAll($event, column)"
[fxLayoutAlign]="column.alignHeader ? column.alignHeader : TableService.alignCellContent(column)">
</mat-checkbox>
</th>
</ng-container>
<ng-container *matCellDef="let result;">
<td mat-cell [ngClass]="TableService.getColumnClassName(column, result)"
*ngIf="onDisplayCell(column, result)"
[ngSwitch]="TableService.getColumnType(column, result)">
<div title="{{column.title(result)}}" *ngSwitchDefault
class="{{TableService.getColumnClassName(column, result)}} viewData"
fxLayout="row" [fxLayoutAlign]="TableService.alignCellContent(column)">
{{ column.cell(result) }}
</div>
<ng-container *ngSwitchCase="ColumnTypes.BUTTON">
<div *ngIf="!!column.button"
class="{{TableService.getColumnClassName(column, result)}}"
fxLayout="row" [fxLayoutAlign]="TableService.alignCellContent(column)"
(click)="$event.stopPropagation()">
<button mat-icon-button color="{{column.button.color}}"
(click)="onClick(column.button.click, result)"
disabled="{{column.button.disabled ? column.button.disabled(result) : false}}"
matTooltip="{{(column.button.title ? column.button.title : '') | translate}}"
class="{{column.button.className}}" [ngSwitch]="TableService.getIconType(column.button)">
<mat-icon *ngSwitchCase="IconTypes.MATERIAL_ICON">{{ column.button.icon }}</mat-icon>
<i *ngSwitchCase="IconTypes.FONT_AWESOME" class="{{column.button.icon}}"></i>
</button>
</div>
</ng-container>
<div class="link viewData"
[ngClass]="{'break-word-style-view': column.hasWordBreakStyle}"
*ngSwitchCase="ColumnTypes.LINK"
fxLayout="row" [fxLayoutAlign]="TableService.alignCellContent(column)"
title="{{column.title(result)}}">
<a [routerLink]="[column.link(result)]">{{ column.cell(result) }}</a>
</div>
<div class="label-status viewData"
[ngClass]="{'break-word-style-view': column.hasWordBreakStyle}"
*ngSwitchCase="ColumnTypes.STYLE_CSS"
fxLayout="row" [fxLayoutAlign]="TableService.alignCellContent(column)"
title="{{column.title(result)}}">
<span [style]="column.style(result)">{{ column.cell(result) }}</span>
</div>
<div class="img-view viewData"
[ngClass]="{'break-word-style-view': column.hasWordBreakStyle}"
*ngSwitchCase="ColumnTypes.IMG"
fxLayout="row" [fxLayoutAlign]="TableService.alignCellContent(column)"
title="{{column.title(result)}}">
<img [src]="column.cell(result) | secure | async" #imgRef
(error)="TableService.onErrorImgEvent(imgRef, config.NO_IMAGE_AVAILABLE)" alt="" />
</div>
<div class="img-view viewData"
[ngClass]="{'break-word-style-view': column.hasWordBreakStyle}"
*ngSwitchCase="ColumnTypes.IMG_NO_SECURE"
fxLayout="row" [fxLayoutAlign]="TableService.alignCellContent(column)"
title="{{column.title(result)}}">
<img [src]="column.cell(result)" #imgRef
(error)="TableService.onErrorImgEvent(imgRef, config.NO_IMAGE_AVAILABLE)" alt="" />
</div>
<div *ngSwitchCase="ColumnTypes.BASE64"
class="img-view viewData"
fxLayout="row" [fxLayoutAlign]="TableService.alignCellContent(column)"
title="{{column.title(result)}}">
<img [src]="'data:image/png;base64,'+column.cell(result)"
#base64ImgRef
(error)="TableService.onErrorImgEvent(base64ImgRef, config.NO_IMAGE_AVAILABLE)" alt="" />
</div>
<ng-container *ngSwitchCase="ColumnTypes.CHECKBOX">
<mat-checkbox [(ngModel)]="result[column.columnDef]" color="primary"
*ngIf="column.display ? column.display(result) : true"
[disabled]="column.disabled ? column.disabled(result) : false"
(change)="toggleSelect($event, result, column)"
[fxLayoutAlign]="TableService.alignCellContent(column)">
</mat-checkbox>
</ng-container>
</td>
</ng-container>
</ng-container>
<ng-container *ngFor="let button of buttons; let i = index" matColumnDef="{{button.columnDef}}">
<ng-container *matHeaderCellDef="let header">
<!-- [fxFlex]="(isButtonHeader(button) ? headerButtonWidthDefault : getHeaderButtonWidth(i)) + 'px' "-->
<!-- [fxFlex]="getHeaderButtonWidth(i) + 'px' "-->
<th mat-header-cell [ngClass]="button.className"
*ngIf="TableService.onDisplayButtonHeaderCell(buttons, button, header, i) && !!buttonColspan"
(click)="$event.stopPropagation()"
[attr.colspan]="buttonColspan"
>
<ng-container *ngIf="TableService.getButtonHeader(button) as btnHeader">
<button mat-icon-button
class="{{button.className}}"
*ngIf="((btnHeader && btnHeader.display) ? btnHeader.display(header) : false) "
[disabled]="((btnHeader && $any(btnHeader).disabled) ? $any(btnHeader).disabled(header) : false) "
color="{{$any(btnHeader).color}}"
(click)="onClick($any(btnHeader).click, null)"
matTooltip="{{((btnHeader && $any(btnHeader).title) ? $any(btnHeader).title : '') | translate}}"
[ngSwitch]="TableService.getIconType($any(btnHeader))">
<mat-icon *ngSwitchCase="IconTypes.MATERIAL_ICON">{{ $any(btnHeader).icon }}</mat-icon>
<i *ngSwitchCase="IconTypes.FONT_AWESOME" class="{{$any(btnHeader).icon}}"></i>
</button>
</ng-container>
<ng-container *ngIf="TableService.getButtonHeaderString(button) as btnHeader">
<div title="{{$any(btnHeader) | translate}}"
class="viewData"
fxLayout="row"
fxLayoutAlign="{{button.alignHeader ? button.alignHeader : AlignEnum.LEFT}} center">
{{ $any(btnHeader) | translate }}
</div>
</ng-container>
</th>
</ng-container>
<ng-container *matCellDef="let cell">
<!-- [fxFlex]="headerButtonWidthDefault + 'px'"-->
<td mat-cell [ngClass]="button.className"
*ngIf="TableService.onDisplayButtonCell(button, cell)"
(click)="$event.stopPropagation()">
<button mat-icon-button color="{{button.color}}"
(click)="onClick(button.click, cell)"
disabled="{{button.disabled ? button.disabled(cell) : false}}"
matTooltip="{{(button.title ? button.title : '') | translate}}"
class="{{button.className}}" [ngSwitch]="TableService.getIconType(button)">
<mat-icon *ngSwitchCase="IconTypes.MATERIAL_ICON">{{ button.icon }}</mat-icon>
<i *ngSwitchCase="IconTypes.FONT_AWESOME" class="{{button.icon}}"></i>
</button>
</td>
</ng-container>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let result; columns: displayedColumns; let i = index"
[ngClass]="result.className"
(click)="onRowClick(result, i)"></tr>
</table>
<div *ngIf="!(loaderService.isLoading | async)">
<div class="paging"
*ngIf="hasData()"
fxLayout fxLayoutAlign="space-between center">
<mat-paginator style-paginator
[showTotalPages]="showTotalPages"
[paging]="varPaging"
(pagingChangeEvent)="getPage($event)"
[length]="varPaging.totalElements"
[pageSize]="varPaging.pageSize"
[pageSizeOptions]="pageSizeOptions"
[pageIndex]="varPaging.pageNumber - 1">
</mat-paginator>
<div class="go-to-page"
fxLayout fxLayoutGap="0.3rem" fxLayoutAlign="start baseline">
<mat-label>{{ 'common.gotopage' | translate }}</mat-label>
<cva-counter-input [(ngModel)]="goToPageNumber"
(ngModelChange)="onChangeGoToPageNumber($event)"
(onEnter)="goToPage()"
[max]="getTotalPage() ? getTotalPage() : 1"
[min]="1"
[isFloatLabel]="false"
[errorMessages]="errorMsg"
></cva-counter-input>
<mat-label style="white-space: nowrap">{{ '/' + getTotalPage() }}</mat-label>
<button mat-flat-button
[disabled]="goToPageNumber < 1 || goToPageNumber > getTotalPage()"
(click)="goToPage()">{{ 'common.go' | translate }}
</button>
</div>
<h2 *ngIf="!hasData()">{{ 'common.no.records.found' | translate }}</h2>
</div>
</div>
</div>
`, isInline: true, dependencies: [{ kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i2.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "directive", type: i2.NgSwitchDefault, selector: "[ngSwitchDefault]" }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i3.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "component", type: i3.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "component", type: i4$1.MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "component", type: i5.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i5.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i5.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i5.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i5.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i5.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i5.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i5.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i5.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i5.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "directive", type: i6.MatLabel, selector: "mat-label" }, { kind: "component", type: i7.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i1$5.MatPaginator, selector: "mat-paginator", inputs: ["color", "pageIndex", "length", "pageSize", "pageSizeOptions", "hidePageSize", "showFirstLastButtons", "selectConfig", "disabled"], outputs: ["page"], exportAs: ["matPaginator"] }, { kind: "directive", type: i8$1.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "directive", type: i1$4.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { kind: "directive", type: i8.DefaultLayoutGapDirective, selector: " [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]", inputs: ["fxLayoutGap", "fxLayoutGap.xs", "fxLayoutGap.sm", "fxLayoutGap.md", "fxLayoutGap.lg", "fxLayoutGap.xl", "fxLayoutGap.lt-sm", "fxLayoutGap.lt-md", "fxLayoutGap.lt-lg", "fxLayoutGap.lt-xl", "fxLayoutGap.gt-xs", "fxLayoutGap.gt-sm", "fxLayoutGap.gt-md", "fxLayoutGap.gt-lg"] }, { kind: "directive", type: i8.DefaultLayoutAlignDirective, selector: " [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]", inputs: ["fxLayoutAlign", "fxLayoutAlign.xs", "fxLayoutAlign.sm", "fxLayoutAlign.md", "fxLayoutAlign.lg", "fxLayoutAlign.xl", "fxLayoutAlign.lt-sm", "fxLayoutAlign.lt-md", "fxLayoutAlign.lt-lg", "fxLayoutAlign.lt-xl", "fxLayoutAlign.gt-xs", "fxLayoutAlign.gt-sm", "fxLayoutAlign.gt-md", "fxLayoutAlign.gt-lg"] }, { kind: "directive", type: i9.DefaultClassDirective, selector: " [ngClass], [ngClass.xs], [ngClass.sm], [ngClass.md], [ngClass.lg], [ngClass.xl], [ngClass.lt-sm], [ngClass.lt-md], [ngClass.lt-lg], [ngClass.lt-xl], [ngClass.gt-xs], [ngClass.gt-sm], [ngClass.gt-md], [ngClass.gt-lg]", inputs: ["ngClass", "ngClass.xs", "ngClass.sm", "ngClass.md", "ngClass.lg", "ngClass.xl", "ngClass.lt-sm", "ngClass.lt-md", "ngClass.lt-lg", "ngClass.lt-xl", "ngClass.gt-xs", "ngClass.gt-sm", "ngClass.gt-md", "ngClass.gt-lg"] }, { kind: "component", type: CvaCounterInputComponent, selector: "cva-counter-input", inputs: ["label", "placeholder", "suffixText", "hint", "value", "disabled", "required", "errorMessages", "min", "max", "error", "isDecimal", "isLabelOutside", "isFloatLabel", "percentOfLabelOutside", "alignNumber", "isFormControl"], outputs: ["onChange", "onEnter"] }, { kind: "directive", type: StylePaginatorDirective, selector: "[style-paginator]", inputs: ["showTotalPages", "paging"], outputs: ["pagingChangeEvent"] }, { kind: "component", type: CvaHeaderExpandButtonComponent, selector: "cva-header-expand-button", inputs: ["expandHeaderButton", "columns", "moduleName"], outputs: ["onChange"] }, { kind: "pipe", type: i2.AsyncPipe, name: "async" }, { kind: "pipe", type: i1.TranslatePipe, name: "translate" }, { kind: "pipe", type: SecureImgPipe, name: "secure" }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: CvaTableComponent, decorators: [{
type: Component,
args: [{
selector: 'cva-table',
standalone: false,
template: `
<div class="table-responsive">
<ng-container *ngIf="!!expandHeaderButton">
<cva-header-expand-button [moduleName]="moduleName" [expandHeaderButton]="expandHeaderButton"
[columns]="columns" (onChange)="this.onChangeDisplayColumn.emit($event)">
</cva-header-expand-button>
</ng-container>
<table mat-table #table [dataSource]="results" class="mat-elevation-z8 cva-table">
<ng-container *ngFor="let column of columns" matColumnDef="{{column.columnDef}}">
<ng-container *matHeaderCellDef>
<th mat-header-cell [ngClass]="TableService.getColumnHeaderClassName(column)"
*ngIf="onDisplayHeaderCell(column)"
[ngSwitch]="TableService.getColumnType(column, null)">
<div fxLayout="row" *ngSwitchDefault
class="viewData"
[ngClass]="{'break-word-style-view': column.hasWordBreakStyle}"
[fxLayoutAlign]="column.alignHeader ? column.alignHeader : TableService.alignCellContent(column)">
{{ TableService.displayHeaderName(column, moduleName) | translate }}
</div>
<mat-checkbox *ngSwitchCase="ColumnTypes.CHECKBOX"
color="primary" class="box-select-all" [(ngModel)]="selectAllChecked"
(change)="toggleSelectAll($event, column)"
[fxLayoutAlign]="column.alignHeader ? column.alignHeader : TableService.alignCellContent(column)">
</mat-checkbox>
</th>
</ng-container>
<ng-container *matCellDef="let result;">
<td mat-cell [ngClass]="TableService.getColumnClassName(column, result)"
*ngIf="onDisplayCell(column, result)"
[ngSwitch]="TableService.getColumnType(column, result)">
<div title="{{column.title(result)}}" *ngSwitchDefault
class="{{TableService.getColumnClassName(column, result)}} viewData"
fxLayout="row" [fxLayoutAlign]="TableService.alignCellContent(column)">
{{ column.cell(result) }}
</div>
<ng-container *ngSwitchCase="ColumnTypes.BUTTON">
<div *ngIf="!!column.button"
class="{{TableService.getColumnClassName(column, result)}}"
fxLayout="row" [fxLayoutAlign]="TableService.alignCellContent(column)"
(click)="$event.stopPropagation()">
<button mat-icon-button color="{{column.button.color}}"
(click)="onClick(column.button.click, result)"
disabled="{{column.button.disabled ? column.button.disabled(result) : false}}"
matTooltip="{{(column.button.title ? column.button.title : '') | translate}}"
class="{{column.button.className}}" [ngSwitch]="TableService.getIconType(column.button)">
<mat-icon *ngSwitchCase="IconTypes.MATERIAL_ICON">{{ column.button.icon }}</mat-icon>
<i *ngSwitchCase="IconTypes.FONT_AWESOME" class="{{column.button.icon}}"></i>
</button>
</div>
</ng-container>
<div class="link viewData"
[ngClass]="{'break-word-style-view': column.hasWordBreakStyle}"
*ngSwitchCase="ColumnTypes.LINK"
fxLayout="row" [fxLayoutAlign]="TableService.alignCellContent(column)"
title="{{column.title(result)}}">
<a [routerLink]="[column.link(result)]">{{ column.cell(result) }}</a>
</div>
<div class="label-status viewData"
[ngClass]="{'break-word-style-view': column.hasWordBreakStyle}"
*ngSwitchCase="ColumnTypes.STYLE_CSS"
fxLayout="row" [fxLayoutAlign]="TableService.alignCellContent(column)"
title="{{column.title(result)}}">
<span [style]="column.style(result)">{{ column.cell(result) }}</span>
</div>
<div class="img-view viewData"
[ngClass]="{'break-word-style-view': column.hasWordBreakStyle}"
*ngSwitchCase="ColumnTypes.IMG"
fxLayout="row" [fxLayoutAlign]="TableService.alignCellContent(column)"
title="{{column.title(result)}}">
<img [src]="column.cell(result) | secure | async" #imgRef
(error)="TableService.onErrorImgEvent(imgRef, config.NO_IMAGE_AVAILABLE)" alt="" />
</div>
<div class="img-view viewData"
[ngClass]="{'break-word-style-view': column.hasWordBreakStyle}"
*ngSwitchCase="ColumnTypes.IMG_NO_SECURE"
fxLayout="row" [fxLayoutAlign]="TableService.alignCellContent(column)"
title="{{column.title(result)}}">
<img [src]="column.cell(result)" #imgRef
(error)="TableService.onErrorImgEvent(imgRef, config.NO_IMAGE_AVAILABLE)" alt="" />
</div>
<div *ngSwitchCase="ColumnTypes.BASE64"
class="img-view viewData"
fxLayout="row" [fxLayoutAlign]="TableService.alignCellContent(column)"
title="{{column.title(result)}}">
<img [src]="'data:image/png;base64,'+column.cell(result)"
#base64ImgRef
(error)="TableService.onErrorImgEvent(base64ImgRef, config.NO_IMAGE_AVAILABLE)" alt="" />
</div>
<ng-container *ngSwitchCase="ColumnTypes.CHECKBOX">
<mat-checkbox [(ngModel)]="result[column.columnDef]" color="primary"
*ngIf="column.display ? column.display(result) : true"
[disabled]="column.disabled ? column.disabled(result) : false"
(change)="toggleSelect($event, result, column)"
[fxLayoutAlign]="TableService.alignCellContent(column)">
</mat-checkbox>
</ng-container>
</td>
</ng-container>
</ng-container>
<ng-container *ngFor="let button of buttons; let i = index" matColumnDef="{{button.columnDef}}">
<ng-container *matHeaderCellDef="let header">
<!-- [fxFlex]="(isButtonHeader(button) ? headerButtonWidthDefault : getHeaderButtonWidth(i)) + 'px' "-->
<!-- [fxFlex]="getHeaderButtonWidth(i) + 'px' "-->
<th mat-header-cell [ngClass]="button.className"
*ngIf="TableService.onDisplayButtonHeaderCell(buttons, button, header, i) && !!buttonColspan"
(click)="$event.stopPropagation()"
[attr.colspan]="buttonColspan"
>
<ng-container *ngIf="TableService.getButtonHeader(button) as btnHeader">
<button mat-icon-button
class="{{button.className}}"
*ngIf="((btnHeader && btnHeader.display) ? btnHeader.display(header) : false) "
[disabled]="((btnHeader && $any(btnHeader).disabled) ? $any(btnHeader).disabled(header) : false) "
color="{{$any(btnHeader).color}}"
(click)="onClick($any(btnHeader).click, null)"
matTooltip="{{((btnHeader && $any(btnHeader).title) ? $any(btnHeader).title : '') | translate}}"
[ngSwitch]="TableService.getIconType($any(btnHeader))">
<mat-icon *ngSwitchCase="IconTypes.MATERIAL_ICON">{{ $any(btnHeader).icon }}</mat-icon>
<i *ngSwitchCase="IconTypes.FONT_AWESOME" class="{{$any(btnHeader).icon}}"></i>
</button>
</ng-container>
<ng-container *ngIf="TableService.getButtonHeaderString(button) as btnHeader">
<div title="{{$any(btnHeader) | translate}}"
class="viewData"
fxLayout="row"
fxLayoutAlign="{{button.alignHeader ? button.alignHeader : AlignEnum.LEFT}} center">
{{ $any(btnHeader) | translate }}
</div>
</ng-container>
</th>
</ng-container>
<ng-container *matCellDef="let cell">
<!-- [fxFlex]="headerButtonWidthDefault + 'px'"-->
<td mat-cell [ngClass]="button.className"
*ngIf="TableService.onDisplayButtonCell(button, cell)"
(click)="$event.stopPropagation()">
<button mat-icon-button color="{{button.color}}"
(click)="onClick(button.click, cell)"
disabled="{{button.disabled ? button.disabled(cell) : false}}"
matTooltip="{{(button.title ? button.title : '') | translate}}"
class="{{button.className}}" [ngSwitch]="TableService.getIconType(button)">
<mat-icon *ngSwitchCase="IconTypes.MATERIAL_ICON">{{ button.icon }}</mat-icon>
<i *ngSwitchCase="IconTypes.FONT_AWESOME" class="{{button.icon}}"></i>
</button>
</td>
</ng-container>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let result; columns: displayedColumns; let i = index"
[ngClass]="result.className"
(click)="onRowClick(result, i)"></tr>
</table>
<div *ngIf="!(loaderService.isLoading | async)">
<div class="paging"
*ngIf="hasData()"
fxLayout fxLayoutAlign="space-between center">
<mat-paginator style-paginator
[showTotalPages]="showTotalPages"
[paging]="varPaging"
(pagingChangeEvent)="getPage($event)"
[length]="varPaging.totalElements"
[pageSize]="varPaging.pageSize"
[pageSizeOptions]="pageSizeOptions"
[pageIndex]="varPaging.pageNumber - 1">
</mat-paginator>
<div class="go-to-page"
fxLayout fxLayoutGap="0.3rem" fxLayoutAlign="start baseline">
<mat-label>{{ 'common.gotopage' | translate }}</mat-label>
<cva-counter-input [(ngModel)]="goToPageNumber"
(ngModelChange)="onChangeGoToPageNumber($event)"
(onEnter)="goToPage()"
[max]="getTotalPage() ? getTotalPage() : 1"
[min]="1"
[isFloatLabel]="false"
[errorMessages]="errorMsg"
></cva-counter-input>
<mat-label style="white-space: nowrap">{{ '/' + getTotalPage() }}</mat-label>
<button mat-flat-button
[disabled]="goToPageNumber < 1 || goToPageNumber > getTotalPage()"
(click)="goToPage()">{{ 'common.go' | translate }}
</button>
</div>
<h2 *ngIf="!hasData()">{{ 'common.no.records.found' | translate }}</h2>
</div>
</div>
</div>
`,
providers: [
{ provide: MatPaginatorIntl, useClass: MultiLanguageTablePaginator },
],
}]
}], ctorParameters: () => [{ type: undefined, decorators: [{
type: Inject,
args: [InjectTokenNextSolutionsConfig]
}] }, { type: i0.ChangeDetectorRef }, { type: LoaderService }], propDecorators: { moduleName: [{
type: Input
}], results: [{
type: Input
}], columns: [{
type: Input
}], buttons: [{
type: Input
}], showTotalPages: [{
type: Input
}], expandHeaderButton: [{
type: Input
}], pagingChange: [{
type: Output
}], clickAction: [{
type: Output
}], onRowClickAction: [{
type: Output
}], onChangeDisplayColumn: [{
type: Output
}], paging: [{
type: Input
}] } });
class PatternDirective {
el;
navigationKeys = [
'Backspace',
'Delete',
'Tab',
'Escape',
'Enter',
'Home',
'End',
'ArrowLeft',
'ArrowRight',
'Clear',
'Copy',
'Paste'
];
set regPattern(reg) {
if (reg) {
this.$regPatternString = reg;
this.$regPattern = new RegExp(reg);
}
}
$regPatternString = '';
$regPattern = new RegExp('');
inputElement;
constructor(el) {
this.el = el;
this.inputElement = el.nativeElement;
}
// @Output() valueChange = new EventEmitter()
// @HostListener('input', ['$event']) onInputChange(event: any) {
// const initalValue = this.el.nativeElement.value;
// const newValue = initalValue.replace(/[^0-9]*/g, '');
// this.el.nativeElement.value = newValue;
// this.valueChange.emit(newValue);
// if ( initalValue !== this.el.nativeElement.value) {
// event.stopPropagation();
// }
// }
onKeyDown(e) {
if (this.navigationKeys.indexOf(e.key) > -1 || // Allow: navigation keys: backspace, delete, arrows etc.
(e.key === 'a' && e.ctrlKey === true) || // Allow: Ctrl+A
(e.key === 'c' && e.ctrlKey === true) || // Allow: Ctrl+C
(e.key === 'v' && e.ctrlKey === true) || // Allow: Ctrl+V
(e.key === 'x' && e.ctrlKey === true) || // Allow: Ctrl+X
(e.key === 'a' && e.metaKey === true) || // Allow: Cmd+A (Mac)
(e.key === 'c' && e.metaKey === true) || // Allow: Cmd+C (Mac)
(e.key === 'v' && e.metaKey === true) || // Allow: Cmd+V (Mac)
(e.key === 'x' && e.metaKey === true) // Allow: Cmd+X (Mac)
) {
// let it happen, don't do anything
return;
}
// Ensure that it is a number and stop the keypress
// if (
// (e.shiftKey || (e.keyCode < 48 || e.keyCode > 57)) &&
// (e.keyCode < 96 || e.keyCode > 105)
// ) {
// e.preventDefault();
// }
if (!e.key.match(this.$regPattern)) {
e.preventDefault();
return;
}
const current = this.el.nativeElement.value;
// @ts-ignore
const next = current ? current.concat(e.key) : e.key;
// @ts-ignore
if (!next || !next.replaceAll(',', '').match(this.$regPattern)) {
e.preventDefault();
}
}
onPaste(event) {
event.preventDefault();
let data = '';
const pastedInput = event.clipboardData?.getData('text/plain'); // get a digit-only string
if (this.$regPatternString !== null && this.$regPatternString !== undefined && this.$regPatternString !== '') {
for (let i = 0; pastedInput && i < pastedInput?.length; i++) {
if (pastedInput[i].match(this.$regPattern)) {
data = data.concat(pastedInput[i]);
}
}
}
else {
data = pastedInput;
}
document.execCommand('insertText', false, data);
}
onDrop(event) {
event.preventDefault();
const textData = event.dataTransfer?.getData('text').replace(/\D/g, '');
this.inputElement.focus();
document.execCommand('insertText', false, textData);
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: PatternDirective, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.1.5", type: PatternDirective, isStandalone: false, selector: "[pattern-directive]", inputs: { regPattern: "regPattern" }, host: { listeners: { "keydown": "onKeyDown($event)", "paste": "onPaste($event)", "drop": "onDrop($event)" } }, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: PatternDirective, decorators: [{
type: Directive,
args: [{
selector: '[pattern-directive]',
standalone: false,
}]
}], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { regPattern: [{
type: Input,
args: ['regPattern']
}], onKeyDown: [{
type: HostListener,
args: ['keydown', ['$event']]
}], onPaste: [{
type: HostListener,
args: ['paste', ['$event']]
}], onDrop: [{
type: HostListener,
args: ['drop', ['$event']]
}] } });
class FormatInputDirective {
element;
elementInput;
control;
inputDirective;
constructor(element) {
this.element = element;
}
_value = '';
get value() {
return this._value;
}
set value(value) {
this._value = value;
this.format(value);
}
input(value) {
// If decimal separator is last character don't update
// because it will delete . || ,
/*
if (this.isLastCharacterDecimalSeparator(value)) {
this._value = value;
} else {
this._value = this.unformatValue(value)
}
*/
// here to notify Angular Validators
this._onChange(value);
// this.format(this._value);
}
focusout(value) {
// If decimal separator is last character don't update
// because it will delete . || ,
if (this.isLastCharacterDecimalSeparator(value)) {
this._value = value;
}
else {
this._value = this.unformatValue(value);
}
// here to notify Angular Validators
this._onChange(this._value);
this.format(this._value);
}
/*
@HostListener('blur')
_onBlur() {
/!**
* Adding thousand separators
*!/
this.format(this._value);
}
*/
_onChange(value) {
}
/**
* @param value
* apply formatting on value assignment
*/
writeValue(value) {
this._value = value;
this.format(this._value);
}
registerOnChange(fn) {
this._onChange = fn;
}
registerOnTouched() {
}
isLastCharacterDecimalSeparator(value) {
return isNaN(value[value.length - 1]);
}
format(value) {
if (value === null) {
this.element.nativeElement.value = '';
return;
}
if (this.isLastCharacterDecimalSeparator(value) && this.elementInput) {
this.element.nativeElement.value = value;
return;
}
if (this.inputDirective && this.inputDirective.formatValue) {
const tmp = this.inputDirective.formatValue(value);
value = tmp === null || tmp === undefined ? value : tmp;
}
this.element.nativeElement.value = value ? value : '';
}
unformatValue(value) {
if (this.inputDirective && this.inputDirective.unformatValue) {
value = this.inputDirective.unformatValue(value);
}
return value;
}
formatValue(value) {
return value;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: FormatInputDirective, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.1.5", type: FormatInputDirective, isStandalone: false, selector: "[inputDirective]", inputs: { inputDirective: "inputDirective", value: "value" }, host: { listeners: { "input": "input($event.target.value)", "focusout": "focusout($event.target.value)" } }, providers: [
{ provide: MAT_INPUT_VALUE_ACCESSOR, useExisting: FormatInputDirective },
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => FormatInputDirective),
multi: true
}
], ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: FormatInputDirective, decorators: [{
type: Directive,
args: [{
selector: '[inputDirective]',
standalone: false,
providers: [
{ provide: MAT_INPUT_VALUE_ACCESSOR, useExisting: FormatInputDirective },
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => FormatInputDirective),
multi: true
}
]
}]
}], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { inputDirective: [{
type: Input,
args: ['inputDirective']
}], value: [{
type: Input,
args: ['value']
}], input: [{
type: HostListener,
args: ['input', ['$event.target.value']]
}], focusout: [{
type: HostListener,
args: ['focusout', ['$event.target.value']]
}] } });
class CvaInputComponent {
injector;
label = '';
name = '';
placeholder = '';
hint = '';
required = false;
disabled = false;
text = '';
type = 'text';
pattern = null;
readonly = false;
errorMessages = new Map();
onChange = new EventEmitter();
multiline = false;
isLabelOutside = false;
isFloatLabel = true;
minLength;
maxLength;
onFocusStatus = false;
/* hiển thị suffix thay maxlength */
maxLengthDisplay;
/* percent label outside css */
percentOfLabelOutside = 25;
suffixFontAwesomeClass = '';
patternFilter = '';
// Chỉ bằng false khi trong NsSmartTable thôi nhé @@
isFormControl = true;
formatFunc;
control = undefined;
get NsValidator() {
return ValidatorService;
}
constructor(injector, ngControl) {
this.injector = injector;
if (ngControl) {
// Hành động này thay cho provide: NG_VALUE_ACCESSOR và gắn ControlValueAccessor này vào parent FormControl
ngControl.valueAccessor = this;
}
}
// Vì không thể quất được NgControl ở constructor nên phải quất ở đây :(
ngAfterViewInit() {
// const ngControl = this.injector.get(NgControl);
// if (ngControl) {
// this.control = ngControl.control;
// this.callValidator();
// }
}
ngOnInit() {
this.callValidator();
}
get textValue() {
return this.text;
}
set textValue(val) {
this.writeValue(val);
}
callValidator() {
const ngControl = this.injector.get(NgControl);
// Nếu parent FormControl khởi tạo xong và formControl chưa có giá trị lưu
if (ngControl && !this.control) {
// Nếu là NsSmartTable thì phải tự new FormControl còn không thì cứ hóng parent FormControl về ^^
if (this.isFormControl) {
this.control = ngControl.control ? ngControl.control : undefined;
}
else {
this.control = new FormControl();
}
// Hành động này gắn validator vào this.formControl
// - Nếu this.formControl là parent FormControl thì sẽ show error lên FormGroup
// - Nếu this.formControl là new FormControl thì sẽ quét QueryList để check {errors}
if (this.control) {
if (this.control.validator) {
this.control.setValidators([...ValidatorService.generateNsInputValidators({
required: this.required,
minLength: this.minLength,
maxLength: this.maxLength,
pattern: this.pattern,
}), this.control.validator]);
}
else {
this.control.setValidators([...ValidatorService.generateNsInputValidators({
required: this.required,
minLength: this.minLength,
maxLength: this.maxLength,
pattern: this.pattern,
})]);
}
}
}
if (this.control) {
// Nếu this.formControl thuộc NsSmartTable thì setValue lại
if (!this.isFormControl) {
this.control.setValue(this.text);
}
// Nếu là parent FormControl rồi thì kệ
this.control.updateValueAndValidity();
}
}
propagateChange = (_) => {
/*NON-EMPTY FOR COMPILE*/
};
/**
* Write a new value to the element.
*/
writeValue(obj) {
this.text = obj;
this.propagateChange(this.text);
this.callValidator();
this.onChange.emit(this.text);
}
/**
* Set the function to be called
* when the formControl receives a change event.
*/
registerOnChange(fn) {
this.propagateChange = fn;
}
/**
* Set the function to be called
* when the formControl receives a touch event.
*/
registerOnTouched() {
/*NON-EMPTY FOR COMPILE*/
}
displayLength() {
if (this.maxLength === null || this.maxLength === undefined) {
return this.maxLengthDisplay ? this.maxLengthDisplay : '';
}
return (this.textValue?.length ? this.textValue.length : 0) + '/' + this.getMaxLength();
}
getMaxLength() {
return this.maxLengthDisplay ? this.maxLengthDisplay : this.maxLength;
}
onFocus() {
this.onFocusStatus = true;
}
onBlur() {
if (this.onFocusStatus) {
this.onFocusStatus = false;
}
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: CvaInputComponent, deps: [{ token: i0.Injector }, { token: i1$2.NgControl, optional: true, self: true }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.5", type: CvaInputComponent, isStandalone: false, selector: "cva-input", inputs: { label: "label", name: "name", placeholder: "placeholder", hint: "hint", required: "required", disabled: "disabled", text: "text", type: "type", pattern: "pattern", readonly: "readonly", errorMessages: "errorMessages", multiline: "multiline", isLabelOutside: "isLabelOutside", isFloatLabel: "isFloatLabel", minLength: "minLength", maxLength: "maxLength", maxLengthDisplay: "maxLengthDisplay", percentOfLabelOutside: "percentOfLabelOutside", suffixFontAwesomeClass: "suffixFontAwesomeClass", patternFilter: "patternFilter", isFormControl: "isFormControl", formatFunc: "formatFunc" }, outputs: { onChange: "onChange" }, ngImport: i0, template: `
<!-- css labelOutside trong base.theme-->
<div class="cva-input"
[ngClass]="{'labelOutside': !!isLabelOutside,
'float_label': !!isFloatLabel && !isLabelOutside,
'text_area': !!this.multiline}"
fxLayout="row" fxLayout.lt-sm="row wrap">
<mat-label *ngIf="isLabelOutside" class="label_width"
fxLayout="column" fxFlex="auto" fxFlex.lt-md="100%">
<div class="label">
<div>
{{(label ? label : placeholder) | translate}}<span class="required-label-outside">{{!!required ? '*' : ''}}</span>
</div>
</div>
</mat-label>
<mat-form-field appearance="outline" [floatLabel]="!!isFloatLabel ? 'always' : 'auto'"
[ngClass]="{'cva-input-multiline': multiline}"
[hideRequiredMarker]="!isFloatLabel"
fxLayout="column" fxFlex="auto" fxFlex.lt-md="100%">
<mat-label *ngIf="!isLabelOutside && !!isFloatLabel" [ngClass]="{'cva-input-multiline': multiline}">
{{(label ? label : placeholder) | translate}}
</mat-label>
<input matInput placeholder="{{placeholder|translate}}" [type]="type" [(ngModel)]="textValue"
[pattern]="pattern"
minLength="{{minLength ? minLength : 0}}"
maxLength="{{maxLength ? maxLength : 524288}}"
[required]="required"
[disabled]="disabled"
readonly="{{readonly}}"
[inputDirective]="formatFunc"
*ngIf="!multiline"
(focus)="onFocus()"
(blur)="onBlur()"
pattern-directive
[regPattern]="patternFilter"
autocomplete="off">
<textarea matInput [(ngModel)]="textValue" placeholder="{{placeholder|translate}}"
[pattern]="pattern"
minLength="{{minLength ? minLength : 0}}"
maxLength="{{maxLength ? maxLength : 524288}}"
[required]="required"
[disabled]="disabled"
readonly="{{readonly}}"
(focus)="onFocus()"
(blur)="onBlur()"
*ngIf="multiline"
cdkTextareaAutosize cdkAutosizeMinRows="3"
autocomplete="off"></textarea>
<i *ngIf="!!suffixFontAwesomeClass" class="input-suffix {{suffixFontAwesomeClass}}" matSuffix></i>
<span *ngIf="onFocusStatus && (!!maxLength || !!maxLengthDisplay)" class="input-suffix"
matSuffix>{{displayLength()}}</span>
<mat-hint align="start" *ngIf="!NsValidator.invalid(control)">{{hint | translate}}</mat-hint>
<mat-hint style="color: red" align="start" *ngIf="NsValidator.invalid(control)">
{{NsValidator.getErrorMessageV1(control, errorMessages).msg | translate: NsValidator.getErrorMessageV1(control, errorMessages).params}}
</mat-hint>
</mat-form-field>
</div>
`, isInline: true, dependencies: [{ kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$2.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i6.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i6.MatLabel, selector: "mat-label" }, { kind: "directive", type: i6.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "directive", type: i6.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "directive", type: i4.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "directive", type: i5$1.CdkTextareaAutosize, selector: "textarea[cdkTextareaAutosize]", inputs: ["cdkAutosizeMinRows", "cdkAutosizeMaxRows", "cdkTextareaAutosize", "placeholder"], exportAs: ["cdkTextareaAutosize"] }, { kind: "directive", type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { kind: "directive", type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { kind: "directive", type: i9.DefaultClassDirective, selector: " [ngClass], [ngClass.xs], [ngClass.sm], [ngClass.md], [ngClass.lg], [ngClass.xl], [ngClass.lt-sm], [ngClass.lt-md], [ngClass.lt-lg], [ngClass.lt-xl], [ngClass.gt-xs], [ngClass.gt-sm], [ngClass.gt-md], [ngClass.gt-lg]", inputs: ["ngClass", "ngClass.xs", "ngClass.sm", "ngClass.md", "ngClass.lg", "ngClass.xl", "ngClass.lt-sm", "ngClass.lt-md", "ngClass.lt-lg", "ngClass.lt-xl", "ngClass.gt-xs", "ngClass.gt-sm", "ngClass.gt-md", "ngClass.gt-lg"] }, { kind: "directive", type: PatternDirective, selector: "[pattern-directive]", inputs: ["regPattern"] }, { kind: "directive", type: FormatInputDirective, selector: "[inputDirective]", inputs: ["inputDirective", "value"] }, { kind: "pipe", type: i1.TranslatePipe, name: "translate" }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: CvaInputComponent, decorators: [{
type: Component,
args: [{
selector: 'cva-input',
standalone: false,
template: `
<!-- css labelOutside trong base.theme-->
<div class="cva-input"
[ngClass]="{'labelOutside': !!isLabelOutside,
'float_label': !!isFloatLabel && !isLabelOutside,
'text_area': !!this.multiline}"
fxLayout="row" fxLayout.lt-sm="row wrap">
<mat-label *ngIf="isLabelOutside" class="label_width"
fxLayout="column" fxFlex="auto" fxFlex.lt-md="100%">
<div class="label">
<div>
{{(label ? label : placeholder) | translate}}<span class="required-label-outside">{{!!required ? '*' : ''}}</span>
</div>
</div>
</mat-label>
<mat-form-field appearance="outline" [floatLabel]="!!isFloatLabel ? 'always' : 'auto'"
[ngClass]="{'cva-input-multiline': multiline}"
[hideRequiredMarker]="!isFloatLabel"
fxLayout="column" fxFlex="auto" fxFlex.lt-md="100%">
<mat-label *ngIf="!isLabelOutside && !!isFloatLabel" [ngClass]="{'cva-input-multiline': multiline}">
{{(label ? label : placeholder) | translate}}
</mat-label>
<input matInput placeholder="{{placeholder|translate}}" [type]="type" [(ngModel)]="textValue"
[pattern]="pattern"
minLength="{{minLength ? minLength : 0}}"
maxLength="{{maxLength ? maxLength : 524288}}"
[required]="required"
[disabled]="disabled"
readonly="{{readonly}}"
[inputDirective]="formatFunc"
*ngIf="!multiline"
(focus)="onFocus()"
(blur)="onBlur()"
pattern-directive
[regPattern]="patternFilter"
autocomplete="off">
<textarea matInput [(ngModel)]="textValue" placeholder="{{placeholder|translate}}"
[pattern]="pattern"
minLength="{{minLength ? minLength : 0}}"
maxLength="{{maxLength ? maxLength : 524288}}"
[required]="required"
[disabled]="disabled"
readonly="{{readonly}}"
(focus)="onFocus()"
(blur)="onBlur()"
*ngIf="multiline"
cdkTextareaAutosize cdkAutosizeMinRows="3"
autocomplete="off"></textarea>
<i *ngIf="!!suffixFontAwesomeClass" class="input-suffix {{suffixFontAwesomeClass}}" matSuffix></i>
<span *ngIf="onFocusStatus && (!!maxLength || !!maxLengthDisplay)" class="input-suffix"
matSuffix>{{displayLength()}}</span>
<mat-hint align="start" *ngIf="!NsValidator.invalid(control)">{{hint | translate}}</mat-hint>
<mat-hint style="color: red" align="start" *ngIf="NsValidator.invalid(control)">
{{NsValidator.getErrorMessageV1(control, errorMessages).msg | translate: NsValidator.getErrorMessageV1(control, errorMessages).params}}
</mat-hint>
</mat-form-field>
</div>
`,
}]
}], ctorParameters: () => [{ type: i0.Injector }, { type: i1$2.NgControl, decorators: [{
type: Self
}, {
type: Optional
}] }], propDecorators: { label: [{
type: Input
}], name: [{
type: Input
}], placeholder: [{
type: Input
}], hint: [{
type: Input
}], required: [{
type: Input
}], disabled: [{
type: Input
}], text: [{
type: Input
}], type: [{
type: Input
}], pattern: [{
type: Input
}], readonly: [{
type: Input
}], errorMessages: [{
type: Input
}], onChange: [{
type: Output
}], multiline: [{
type: Input
}], isLabelOutside: [{
type: Input
}], isFloatLabel: [{
type: Input
}], minLength: [{
type: Input
}], maxLength: [{
type: Input
}], maxLengthDisplay: [{
type: Input
}], percentOfLabelOutside: [{
type: Input
}], suffixFontAwesomeClass: [{
type: Input
}], patternFilter: [{
type: Input
}], isFormControl: [{
type: Input
}], formatFunc: [{
type: Input
}] } });
class NsDateAdapter extends NativeDateAdapter {
format(date, displayFormat) {
let day = date.getDate().toString();
day = +day < 10 ? '0' + day : day;
let month = (date.getMonth() + 1).toString();
month = +month < 10 ? '0' + month : month;
const year = date.getFullYear();
if (displayFormat === 'input') {
return `${day}/${month}/${year}`;
}
return `${month}/${year}`;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: NsDateAdapter, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: NsDateAdapter });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: NsDateAdapter, decorators: [{
type: Injectable
}] });
const APP_DATE_FORMATS = {
parse: {
dateInput: { month: 'short', year: 'numeric', day: 'numeric' },
},
display: {
dateInput: 'input',
monthYearLabel: { year: 'numeric', month: 'numeric' },
dateA11yLabel: { year: 'numeric', month: 'long', day: 'numeric' },
monthYearA11yLabel: { year: 'numeric', month: 'long' },
},
};
class DateUtilService {
datePipe;
injector;
config;
DIS_DATE_TIME_FORMAT_DEFAULT = 'dd/MM/yyyy HH:mm';
constructor(datePipe, injector) {
this.datePipe = datePipe;
this.injector = injector;
this.config = injector.get(InjectTokenNextSolutionsConfig);
}
getDateNow() {
const now = new Date();
return new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0);
}
addDays(date, days) {
date.setDate(date.getDate() + days);
return date;
}
convertToStartOfDate(dateString) {
const currentDate = this.convertToDateIgnoreTimeZone(dateString);
if (currentDate) {
return new Date(currentDate.getFullYear(), currentDate.getMonth(), currentDate.getDate(), 0, 0, 0);
}
return new Date(1900, 1, 1);
}
convertDateToStringCurrentGMT(date) {
return this.datePipe.transform(date, this.config.API_DATE_FORMAT);
}
convertDateToStringGMT0(date) {
return this.datePipe.transform(date, this.config.API_DATE_FORMAT, '-0');
}
convertDateToDisplayGMT0(date) {
return this.datePipe.transform(date, this.config.DIS_DATE_FORMAT, '-0');
}
convertDateToDisplayServerTime(date) {
return this.datePipe.transform(date ? date.replace('Z', '') : '', this.config.DIS_DATE_FORMAT);
}
convertDateTimeToDisplay(date) {
return this.datePipe.transform(date.replace('Z', ''), this.config.DIS_DATE_TIME_FORMAT ? this.config.DIS_DATE_TIME_FORMAT : this.DIS_DATE_TIME_FORMAT_DEFAULT);
}
convertToDateIgnoreTimeZone(dateStr) {
if (dateStr != null) {
return new Date(dateStr.replace('Z', ''));
}
else {
return null;
}
}
convertStringToDate(date) {
return date ? new Date(date.replace(' ', 'T')) : new Date(1900, 1, 1);
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: DateUtilService, deps: [{ token: i2.DatePipe }, { token: i0.Injector }], target: i0.ɵɵFactoryTarget.Injectable });
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: DateUtilService, providedIn: 'root' });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: DateUtilService, decorators: [{
type: Injectable,
args: [{ providedIn: 'root' }]
}], ctorParameters: () => [{ type: i2.DatePipe }, { type: i0.Injector }] });
class CvaDatePickerComponent {
dateServiceUtil;
injector;
label = '';
placeholder = '';
value;
disabled = false;
required = false;
minDate = new Date(1900, 1, 1);
maxDate = new Date(9999, 12, 31);
onChange = new EventEmitter();
errorMessages = new Map();
isLabelOutside = false;
isFloatLabel = true;
/* percent label outside css */
percentOfLabelOutside = 25;
title = null;
config;
// Chỉ bằng false khi trong NsSmartTable thôi @@
isFormControl = true;
formControl;
get NsValidator() {
return ValidatorService;
}
constructor(dateServiceUtil, ngControl, injector) {
this.dateServiceUtil = dateServiceUtil;
this.injector = injector;
this.config = injector.get(InjectTokenNextSolutionsConfig);
if (ngControl) {
// Hành động này thay cho provide: NG_VALUE_ACCESSOR và gắn ControlValueAccessor này vào parent FormControl
ngControl.valueAccessor = this;
}
}
ngOnInit() {
this.callValidator();
}
callValidator() {
const ngControl = this.injector.get(NgControl);
// Nếu parent FormControl khởi tạo xong và formControl chưa có giá trị lưu
if (ngControl && !this.formControl) {
// Nếu là NsSmartTable thì phải tự new FormControl còn không thì cứ hóng parent FormControl về ^^
if (this.isFormControl) {
this.formControl = ngControl.control ? ngControl.control : undefined;
}
else {
this.formControl = new FormControl();
}
// Hành động này gắn validator vào this.formControl
// - Nếu this.formControl là parent FormControl thì sẽ show error lên FormGroup
// - Nếu this.formControl là new FormControl thì sẽ quét QueryList để check {errors}
if (this.formControl) {
this.formControl.setValidators(ValidatorService.generateNsDatePickerValidators({
required: this.required,
min: this.getMinDate(),
max: this.getMaxDate(),
}));
}
}
if (this.formControl) {
// Nếu this.formControl thuộc NsSmartTable thì setValue lại
if (!this.isFormControl) {
this.formControl.setValue(this.value);
}
// Nếu là parent FormControl rồi thì kệ
this.formControl.updateValueAndValidity();
const errorsObj = {};
const errors = this.formControl.errors;
if (errors) {
Object.keys(errors).forEach(key => {
errorsObj[key] = errors[key];
});
}
const minValidation = ValidatorService.customMinDateValidatorControl(this.value, this.getMinDate());
if (minValidation) {
Object.keys(minValidation).forEach(key => {
errorsObj[key] = minValidation[key];
});
}
const maxValidation = ValidatorService.customMaxDateValidatorControl(this.value, this.getMaxDate());
if (maxValidation) {
Object.keys(maxValidation).forEach(key => {
errorsObj[key] = maxValidation[key];
});
}
if (Object.keys(errorsObj).length > 0) {
this.formControl.setErrors(errorsObj);
}
else {
this.formControl.setErrors(null);
}
this.formControl.markAllAsTouched();
}
}
checkRequired(isRequired) {
return isRequired ? typeof (isRequired) === 'boolean' ? isRequired : isRequired() : false;
}
get datepickerValue() {
if (this.value instanceof Date) {
return this.value;
}
if (this.isString(this.value) && this.value.indexOf('Z') >= 0) {
return this.value.replace(' ', 'T');
}
return null;
}
set datepickerValue(val) {
this.writeValue(val);
}
propagateChange = (_) => {
/*NON-EMPTY FOR COMPILE*/
};
registerOnChange(fn) {
this.propagateChange = fn;
}
registerOnTouched(fn) {
/*NON-EMPTY FOR COMPILE*/
}
writeValue(obj) {
let out = '';
this.value = obj;
if (obj) {
// Nếu là dạng server trả về là string và có Z thì thuộc GMT+0 nên sẽ ép về zone -0
if (this.isString(this.value) && this.value.indexOf('Z') >= 0) {
out = this.dateServiceUtil.convertDateToStringGMT0(obj);
}
else {
out = this.dateServiceUtil.convertDateToStringCurrentGMT(this.value);
}
}
if (out) {
this.title = this.dateServiceUtil.convertDateToDisplayGMT0(out);
}
this.propagateChange(out);
this.callValidator();
this.onChange.emit(out ? out : '');
}
onClear() {
this.writeValue(null);
}
getMinDate() {
if (this.minDate) {
return this.minDate instanceof Date ? this.minDate : this.minDate();
}
return new Date(1900, 1, 1);
}
getMaxDate() {
if (this.maxDate) {
return this.maxDate instanceof Date ? this.maxDate : this.maxDate();
}
return new Date(9999, 12, 31);
}
isString(inputValue) {
return typeof inputValue === 'string' || inputValue instanceof String;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: CvaDatePickerComponent, deps: [{ token: DateUtilService }, { token: i1$2.NgControl, optional: true, self: true }, { token: i0.Injector }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.5", type: CvaDatePickerComponent, isStandalone: false, selector: "cva-date-picker", inputs: { label: "label", placeholder: "placeholder", value: "value", disabled: "disabled", required: "required", minDate: "minDate", maxDate: "maxDate", errorMessages: "errorMessages", isLabelOutside: "isLabelOutside", isFloatLabel: "isFloatLabel", percentOfLabelOutside: "percentOfLabelOutside", isFormControl: "isFormControl" }, outputs: { onChange: "onChange" }, providers: [
{ provide: DateAdapter, useClass: NsDateAdapter },
{
provide: MAT_DATE_FORMATS,
useValue: APP_DATE_FORMATS,
},
], ngImport: i0, template: `
<!-- css labelOutside trong base.theme-->
<div class="cva-date-picker"
[ngClass]="{'labelOutside': isLabelOutside, 'float_label': isFloatLabel && !isLabelOutside}"
fxLayout="row" fxLayout.lt-sm="row wrap">
<mat-label *ngIf="isLabelOutside" class="label_width"
fxLayout="column" fxFlex="auto" fxFlex.lt-md="100%">
<div class="label">
<div>
{{ (label ? label : placeholder) | translate }}<span
class="required-label-outside">{{ !!required ? '*' : '' }}</span>
</div>
</div>
</mat-label>
<mat-form-field appearance="outline" [floatLabel]="isFloatLabel ? 'always' : 'auto'"
[hideRequiredMarker]="!isFloatLabel"
fxLayout="column" fxFlex="auto" fxFlex.lt-md="100%">
<mat-label *ngIf="!isLabelOutside && isFloatLabel">{{ (label ? label : placeholder) | translate }}</mat-label>
<input matInput [matDatepicker]="xDatepicker"
[placeholder]="placeholder|translate"
[(ngModel)]="datepickerValue"
[readonly]="true"
[required]="checkRequired(required)"
[title]="title ? title : ''"
[min]="getMinDate()" [max]="getMaxDate()">
<mat-datepicker-toggle matPrefix [for]="xDatepicker" [disabled]="disabled"></mat-datepicker-toggle>
<mat-datepicker #xDatepicker></mat-datepicker>
<button mat-icon-button color="warn" class="btnDatePicker" matSuffix (click)="onClear()"
[disabled]="disabled || checkRequired(required)">
<mat-icon>clear</mat-icon>
</button>
<mat-hint style="color: red" *ngIf="NsValidator.invalid(formControl)">
{{ NsValidator.getErrorMessage(formControl, errorMessages) | translate }}
</mat-hint>
</mat-form-field>
</div>
`, isInline: true, dependencies: [{ kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i3.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "component", type: i5$2.MatDatepicker, selector: "mat-datepicker", exportAs: ["matDatepicker"] }, { kind: "directive", type: i5$2.MatDatepickerInput, selector: "input[matDatepicker]", inputs: ["matDatepicker", "min", "max", "matDatepickerFilter"], exportAs: ["matDatepickerInput"] }, { kind: "component", type: i5$2.MatDatepickerToggle, selector: "mat-datepicker-toggle", inputs: ["for", "tabIndex", "aria-label", "disabled", "disableRipple"], exportAs: ["matDatepickerToggle"] }, { kind: "component", type: i6.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i6.MatLabel, selector: "mat-label" }, { kind: "directive", type: i6.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "directive", type: i6.MatPrefix, selector: "[matPrefix], [matIconPrefix], [matTextPrefix]", inputs: ["matTextPrefix"] }, { kind: "directive", type: i6.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "component", type: i7.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: i4.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "directive", type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { kind: "directive", type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { kind: "directive", type: i9.DefaultClassDirective, selector: " [ngClass], [ngClass.xs], [ngClass.sm], [ngClass.md], [ngClass.lg], [ngClass.xl], [ngClass.lt-sm], [ngClass.lt-md], [ngClass.lt-lg], [ngClass.lt-xl], [ngClass.gt-xs], [ngClass.gt-sm], [ngClass.gt-md], [ngClass.gt-lg]", inputs: ["ngClass", "ngClass.xs", "ngClass.sm", "ngClass.md", "ngClass.lg", "ngClass.xl", "ngClass.lt-sm", "ngClass.lt-md", "ngClass.lt-lg", "ngClass.lt-xl", "ngClass.gt-xs", "ngClass.gt-sm", "ngClass.gt-md", "ngClass.gt-lg"] }, { kind: "pipe", type: i1.TranslatePipe, name: "translate" }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: CvaDatePickerComponent, decorators: [{
type: Component,
args: [{
selector: 'cva-date-picker',
standalone: false,
template: `
<!-- css labelOutside trong base.theme-->
<div class="cva-date-picker"
[ngClass]="{'labelOutside': isLabelOutside, 'float_label': isFloatLabel && !isLabelOutside}"
fxLayout="row" fxLayout.lt-sm="row wrap">
<mat-label *ngIf="isLabelOutside" class="label_width"
fxLayout="column" fxFlex="auto" fxFlex.lt-md="100%">
<div class="label">
<div>
{{ (label ? label : placeholder) | translate }}<span
class="required-label-outside">{{ !!required ? '*' : '' }}</span>
</div>
</div>
</mat-label>
<mat-form-field appearance="outline" [floatLabel]="isFloatLabel ? 'always' : 'auto'"
[hideRequiredMarker]="!isFloatLabel"
fxLayout="column" fxFlex="auto" fxFlex.lt-md="100%">
<mat-label *ngIf="!isLabelOutside && isFloatLabel">{{ (label ? label : placeholder) | translate }}</mat-label>
<input matInput [matDatepicker]="xDatepicker"
[placeholder]="placeholder|translate"
[(ngModel)]="datepickerValue"
[readonly]="true"
[required]="checkRequired(required)"
[title]="title ? title : ''"
[min]="getMinDate()" [max]="getMaxDate()">
<mat-datepicker-toggle matPrefix [for]="xDatepicker" [disabled]="disabled"></mat-datepicker-toggle>
<mat-datepicker #xDatepicker></mat-datepicker>
<button mat-icon-button color="warn" class="btnDatePicker" matSuffix (click)="onClear()"
[disabled]="disabled || checkRequired(required)">
<mat-icon>clear</mat-icon>
</button>
<mat-hint style="color: red" *ngIf="NsValidator.invalid(formControl)">
{{ NsValidator.getErrorMessage(formControl, errorMessages) | translate }}
</mat-hint>
</mat-form-field>
</div>
`,
providers: [
{ provide: DateAdapter, useClass: NsDateAdapter },
{
provide: MAT_DATE_FORMATS,
useValue: APP_DATE_FORMATS,
},
],
}]
}], ctorParameters: () => [{ type: DateUtilService }, { type: i1$2.NgControl, decorators: [{
type: Self
}, {
type: Optional
}] }, { type: i0.Injector }], propDecorators: { label: [{
type: Input
}], placeholder: [{
type: Input
}], value: [{
type: Input
}], disabled: [{
type: Input
}], required: [{
type: Input
}], minDate: [{
type: Input
}], maxDate: [{
type: Input
}], onChange: [{
type: Output
}], errorMessages: [{
type: Input
}], isLabelOutside: [{
type: Input
}], isFloatLabel: [{
type: Input
}], percentOfLabelOutside: [{
type: Input
}], isFormControl: [{
type: Input
}] } });
class CvaMultiSelectAutocomplete {
translateService;
injector;
placeholder = '';
label = '';
hint = '';
value = [];
options = [];
disabled = false;
errorMessages = new Map();
multiple = true;
required = false;
isTree = false;
treeSymbol = ' >> ';
sizeOfItemsInListByPixels = 39;
isLabelOutside = false;
isFloatLabel = true;
/* percent label outside css */
percentOfLabelOutside = 25;
selectionChange = new EventEmitter();
selectedOptionDataChange = new EventEmitter();
valueOptionRef = [];
// Chỉ bằng false khi trong NsSmartTable thôi nhé @@
isFormControl = true;
searchInputRef;
// Cái này là để gắn khi nó là FormControl trong 1 FormGroup
formControl;
filteredOptions = [];
selectAllChecked = false;
labelCount = 1;
cdkVirtualScrollViewPort;
constructor(translateService, injector, ngControl) {
this.translateService = translateService;
this.injector = injector;
if (ngControl) {
ngControl.valueAccessor = this;
}
}
_displayString = '';
get displayString() {
return this._displayString;
}
get NsValidator() {
return ValidatorService;
}
get selectedValue() {
return this.value;
}
set selectedValue(val) {
// this.writeValue(val); // Đọc comment bên dưới matSelectionChange
}
ngOnInit() {
this.callValidator();
}
getRequired() {
return typeof this.required === 'function' ? this.required() : this.required;
}
callValidator() {
const ngControl = this.injector.get(NgControl);
if (ngControl && !this.formControl) {
// Nếu là NsSmartTable thì phải tự new FormControl còn không thì cứ hóng parent FormControl về ^^
if (this.isFormControl) {
this.formControl = ngControl.control ? ngControl.control : undefined;
}
else {
this.formControl = new FormControl();
}
if (this.formControl) {
this.formControl.setValidators(ValidatorService.generateNsMultiSelectValidators({
required: this.required,
multiple: this.multiple,
}));
}
}
if (this.formControl) {
// Nếu this.formControl thuộc NsSmartTable thì setValue lại
if (!this.isFormControl) {
this.formControl.setValue(this.value);
}
this.formControl.updateValueAndValidity();
}
}
propagateChange = (_) => {
/*NON-EMPTY FOR COMPILE*/
};
writeValue(obj) {
if (obj != null && obj != undefined && this.value !== obj) {
this.value = obj;
this.updateSelectAll();
// this.formControl.setValue(this.value);
this.propagateChange(this.value);
this.callValidator();
this.selectionChange.emit(this.value);
}
if (obj != null && obj != undefined && !((this.multiple && this.value.length === this.valueOptionRef.length)
|| (!this.multiple && this.valueOptionRef[0] && this.value === this.valueOptionRef[0].value))) {
if (this.multiple) {
this.valueOptionRef = this.options.filter(option => this.value.includes(option.value));
}
else {
this.valueOptionRef = this.options.filter(option => this.value === option.value);
}
this.selectedOptionDataChange.emit(this.valueOptionRef);
}
this._displayString = this.onDisplayString();
}
registerOnChange(fn) {
this.propagateChange = fn;
}
registerOnTouched() {
/*NON-EMPTY FOR COMPILE*/
}
ngOnChanges(simpleChanges) {
if ('options' in simpleChanges) {
this.options = simpleChanges.options.currentValue;
this.filteredOptions = this.options;
}
if (this.value != null) {
this.writeValue(this.value);
}
}
toggleSelectAll(val) {
if (val.checked) {
let tempChecked = this.value ? this.value : [];
this.filteredOptions.forEach((option) => {
if ((!this.value || (this.value && !this.value.includes(option.value))) && !option.disabled) {
tempChecked = tempChecked.concat([option.value]);
}
});
this.writeValue(tempChecked);
this.selectedOptionDataChange.emit(this.filteredOptions.filter((option) => !option.disabled));
}
else {
const filteredValues = [];
this.filteredOptions.forEach((option) => {
if (!option.disabled) {
filteredValues.push(option.value);
}
});
const filteredSelectedValue = this.value.filter((item) => !filteredValues.includes(item));
this.writeValue(filteredSelectedValue);
this.selectedOptionDataChange.emit([]);
}
this.selectionChange.emit(this.value);
}
filterItem(value) {
this.filteredOptions = this.options.filter((item) => {
const translatedDisplayValue = this.translateService.instant(item.displayValue);
if (translatedDisplayValue) {
return translatedDisplayValue.toLowerCase().indexOf(value.toLowerCase().trim()) > -1;
}
else {
return item.displayValue.toLowerCase().indexOf(value.toLowerCase().trim()) > -1;
}
});
this.selectAllChecked = !!this.value;
this.filteredOptions.forEach((item) => {
if (this.value instanceof Array && !this.value.includes(item.value)) {
this.selectAllChecked = false;
}
});
}
onDisplayString() {
let _displayString = '';
if (this.value !== null && this.value !== undefined && this.value !== ''
&& (!this.multiple || this.value.length > 0)) {
let displayOptions = [];
if (this.multiple) {
// Multi select display
for (let i = 0; i < this.labelCount; i++) {
displayOptions[i] = this.options.filter(option => option.value === this.value[i])[0];
}
if (displayOptions.length) {
for (const displayOption of displayOptions) {
_displayString += displayOption
? ((this.isTree ? this.onDisplayTreeData(displayOption.displayValue, true) : displayOption.displayValue) + ',')
: '';
}
_displayString = _displayString.slice(0, -1);
if (this.value.length > 1) {
const strOthers = this.translateService.instant('common.others');
_displayString += ` (+${this.value.length - this.labelCount} ${strOthers})`;
}
}
}
else {
// Single select display
displayOptions = this.options.filter(option => option.value === this.value);
if (displayOptions.length) {
_displayString = this.isTree
? this.onDisplayTreeData(displayOptions[0].displayValue, true)
: displayOptions[0].displayValue;
}
}
}
return _displayString;
}
/* Nếu không dùng virtual scroll thì mat-options trong mat-select được load hết
* Khi toàn bộ mat-options được load hết thì mat-select-trigger sẽ lưu trữ được các giá trị đã chọn
* Khi chọn 1 hay nhiều thì val.value sẽ là toàn bộ giá trị đã chọn
*/
/* Khi dùng virtual scroll thì mình chỉ load nhẹ 1 mat-options đầu đã chọn để hack speed displayOptions
* Khi đó khi chọn lại thì những mat-option không còn trong khung nhìn sẽ bị lỗi tick chọn nên ko dùng hàm này nữa
*/
matSelectionChange(val) {
// this.writeValue(val.value);
// this.emitSelectedData(val);
}
onSelectionChange(change) {
if (!change.isUserInput) {
return;
}
const value = change.source.value;
if (!this.multiple) {
this.writeValue(value);
return;
}
const idx = this.value.indexOf(value);
let tempChecked = this.value ? this.value : [];
if (idx > -1) {
tempChecked = tempChecked.filter(x => x !== value);
}
else {
tempChecked = tempChecked.concat([value]);
}
this.writeValue(tempChecked);
}
updateSelectAll() {
const filteredValues = [];
this.filteredOptions.forEach((option) => {
if (!option.disabled) {
filteredValues.push(option.value);
}
});
let count = 0;
if (this.multiple && this.value && this.value instanceof Array && filteredValues) {
this.value.forEach((item) => {
count++;
});
this.selectAllChecked = count > 0 && count === filteredValues.length;
}
}
onDisplayTreeData(displayValue, isFirstLine) {
const lastIndex = displayValue.lastIndexOf(this.treeSymbol.trim());
if (lastIndex < 0) {
return displayValue;
}
if (isFirstLine) {
return this.translateService.instant(displayValue.substr(lastIndex).replace(this.treeSymbol.trim(), '').trim());
}
else {
const preValue = displayValue.substr(0, lastIndex).trim();
const preValues = preValue.split(this.treeSymbol.trim());
let result = '';
for (const value of preValues) {
result += this.translateService.instant(value.trim()) + ' ' + this.treeSymbol.trim() + ' ';
}
return result ? result.substr(0, result.length - 4) : result;
}
}
openChange($event) {
if ($event) {
if (this.cdkVirtualScrollViewPort) {
this.cdkVirtualScrollViewPort.scrollToIndex(0);
this.cdkVirtualScrollViewPort.checkViewportSize();
}
setTimeout(() => {
if (this.searchInputRef?.nativeElement) {
this.searchInputRef.nativeElement.focus();
}
}, 300);
}
}
getItemSize() {
return this.sizeOfItemsInListByPixels;
}
getViewPortHeight() {
const numberOfItems = this.options.length > 10 ? 10 : this.options.length;
const height = numberOfItems * this.sizeOfItemsInListByPixels;
return height > 200 ? 200 : height;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: CvaMultiSelectAutocomplete, deps: [{ token: i1.TranslateService }, { token: i0.Injector }, { token: i1$2.NgControl, optional: true, self: true }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.5", type: CvaMultiSelectAutocomplete, isStandalone: false, selector: "cva-multi-select-autocomplete", inputs: { placeholder: "placeholder", label: "label", hint: "hint", value: "value", options: "options", disabled: "disabled", errorMessages: "errorMessages", multiple: "multiple", required: "required", isTree: "isTree", treeSymbol: "treeSymbol", sizeOfItemsInListByPixels: "sizeOfItemsInListByPixels", isLabelOutside: "isLabelOutside", isFloatLabel: "isFloatLabel", percentOfLabelOutside: "percentOfLabelOutside", isFormControl: "isFormControl" }, outputs: { selectionChange: "selectionChange", selectedOptionDataChange: "selectedOptionDataChange" }, viewQueries: [{ propertyName: "searchInputRef", first: true, predicate: ["searchInput"], descendants: true }, { propertyName: "cdkVirtualScrollViewPort", first: true, predicate: CdkVirtualScrollViewport, descendants: true }], usesOnChanges: true, ngImport: i0, template: `
<!-- css labelOutside trong base.theme-->
<div class="cva-multi-select-autocomplete"
[ngClass]="{'labelOutside': !!isLabelOutside, 'float_label': !!isFloatLabel && !isLabelOutside}"
fxLayout="row" fxLayout.lt-sm="row wrap">
<mat-label *ngIf="isLabelOutside" class="label_width"
fxLayout="column" fxFlex="auto" fxFlex.lt-md="100%">
<div class="label">
<div>
{{ (label ? label : placeholder) | translate }}<span
class="required-label-outside">{{ !!getRequired() ? '*' : '' }}</span>
</div>
</div>
</mat-label>
<mat-form-field appearance="outline" [floatLabel]="!!isFloatLabel ? 'always' : 'auto'"
[hideRequiredMarker]="!isFloatLabel"
fxLayout="column" fxFlex="auto" fxFlex.lt-md="100%">
<mat-label
*ngIf="!isLabelOutside && !!isFloatLabel">{{ (label ? label : placeholder) | translate }}
</mat-label>
<mat-select [disabled]="disabled"
[placeholder]="placeholder | translate"
[multiple]="multiple"
[(ngModel)]="selectedValue"
[required]="getRequired()"
(selectionChange)="matSelectionChange($event)"
(openedChange)="openChange($event)">
<div class="box-search">
<mat-checkbox *ngIf="multiple" color="primary" class="box-select-all"
[(ngModel)]="selectAllChecked"
(change)="toggleSelectAll($event)"></mat-checkbox>
<input #searchInput type="text" [ngClass]="{'pl-1': !multiple}"
(keydown.space)="$event.stopPropagation()"
(input)="filterItem(searchInput.value)"
placeholder="{{'btnSearch' | translate}}...">
<div class="box-search-icon" (click)="filterItem(''); searchInput.value = ''">
<button mat-icon-button class="search-button">
<mat-icon class="mat-24" aria-label="Search icon">clear</mat-icon>
</button>
</div>
</div>
<mat-select-trigger title="{{displayString|translate}}">
{{ displayString | translate }}
</mat-select-trigger>
<cdk-virtual-scroll-viewport [itemSize]="getItemSize()"
[style.height.px]="getViewPortHeight()">
<mat-option *cdkVirtualFor="let option of filteredOptions; let i = index"
[attr.data-optionIndex]="i"
[disabled]="option.disabled" [value]="option.value"
[ngClass]="{'tree-mat-option': isTree}"
title="{{option.displayValue|translate}}"
(onSelectionChange)="onSelectionChange($event)">
<div *ngIf="!isTree">{{ option.displayValue | translate }}</div>
<div *ngIf="!!isTree" class="tree-multiline-mat-option">
<div mat-line>{{ onDisplayTreeData(option.displayValue, true) }}</div>
<p mat-line>{{ onDisplayTreeData(option.displayValue, false) }}</p>
</div>
</mat-option>
</cdk-virtual-scroll-viewport>
<ng-container *ngIf="multiple">
<ng-container *ngFor="let option of selectedValue; let i = index">
<mat-option class="selected-options" [value]="option" *ngIf="i===0">
{{ option }}
</mat-option>
</ng-container>
</ng-container>
<ng-container *ngIf="!multiple">
<mat-option class="selected-options" *ngIf="!!selectedValue"
[value]="selectedValue">{{ selectedValue }}
</mat-option>
</ng-container>
</mat-select>
<mat-icon matSuffix>expand_more</mat-icon>
<mat-hint *ngIf="!NsValidator.invalid(formControl)">{{ hint | translate }}</mat-hint>
<mat-hint style="color: red" *ngIf="NsValidator.invalid(formControl)">
{{ NsValidator.getErrorMessage(formControl, errorMessages) | translate }}
</mat-hint>
</mat-form-field>
</div>
`, isInline: true, dependencies: [{ kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i4$2.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "component", type: i3.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "component", type: i4$1.MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "component", type: i6.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i6.MatLabel, selector: "mat-label" }, { kind: "directive", type: i6.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "directive", type: i6.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "directive", type: i4$2.MatLine, selector: "[mat-line], [matLine]" }, { kind: "component", type: i7.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i9$1.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "directive", type: i9$1.MatSelectTrigger, selector: "mat-select-trigger" }, { kind: "directive", type: i10.CdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { kind: "directive", type: i10.CdkVirtualForOf, selector: "[cdkVirtualFor][cdkVirtualForOf]", inputs: ["cdkVirtualForOf", "cdkVirtualForTrackBy", "cdkVirtualForTemplate", "cdkVirtualForTemplateCacheSize"] }, { kind: "component", type: i10.CdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }, { kind: "directive", type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { kind: "directive", type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { kind: "directive", type: i9.DefaultClassDirective, selector: " [ngClass], [ngClass.xs], [ngClass.sm], [ngClass.md], [ngClass.lg], [ngClass.xl], [ngClass.lt-sm], [ngClass.lt-md], [ngClass.lt-lg], [ngClass.lt-xl], [ngClass.gt-xs], [ngClass.gt-sm], [ngClass.gt-md], [ngClass.gt-lg]", inputs: ["ngClass", "ngClass.xs", "ngClass.sm", "ngClass.md", "ngClass.lg", "ngClass.xl", "ngClass.lt-sm", "ngClass.lt-md", "ngClass.lt-lg", "ngClass.lt-xl", "ngClass.gt-xs", "ngClass.gt-sm", "ngClass.gt-md", "ngClass.gt-lg"] }, { kind: "pipe", type: i1.TranslatePipe, name: "translate" }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: CvaMultiSelectAutocomplete, decorators: [{
type: Component,
args: [{
selector: 'cva-multi-select-autocomplete',
standalone: false,
template: `
<!-- css labelOutside trong base.theme-->
<div class="cva-multi-select-autocomplete"
[ngClass]="{'labelOutside': !!isLabelOutside, 'float_label': !!isFloatLabel && !isLabelOutside}"
fxLayout="row" fxLayout.lt-sm="row wrap">
<mat-label *ngIf="isLabelOutside" class="label_width"
fxLayout="column" fxFlex="auto" fxFlex.lt-md="100%">
<div class="label">
<div>
{{ (label ? label : placeholder) | translate }}<span
class="required-label-outside">{{ !!getRequired() ? '*' : '' }}</span>
</div>
</div>
</mat-label>
<mat-form-field appearance="outline" [floatLabel]="!!isFloatLabel ? 'always' : 'auto'"
[hideRequiredMarker]="!isFloatLabel"
fxLayout="column" fxFlex="auto" fxFlex.lt-md="100%">
<mat-label
*ngIf="!isLabelOutside && !!isFloatLabel">{{ (label ? label : placeholder) | translate }}
</mat-label>
<mat-select [disabled]="disabled"
[placeholder]="placeholder | translate"
[multiple]="multiple"
[(ngModel)]="selectedValue"
[required]="getRequired()"
(selectionChange)="matSelectionChange($event)"
(openedChange)="openChange($event)">
<div class="box-search">
<mat-checkbox *ngIf="multiple" color="primary" class="box-select-all"
[(ngModel)]="selectAllChecked"
(change)="toggleSelectAll($event)"></mat-checkbox>
<input #searchInput type="text" [ngClass]="{'pl-1': !multiple}"
(keydown.space)="$event.stopPropagation()"
(input)="filterItem(searchInput.value)"
placeholder="{{'btnSearch' | translate}}...">
<div class="box-search-icon" (click)="filterItem(''); searchInput.value = ''">
<button mat-icon-button class="search-button">
<mat-icon class="mat-24" aria-label="Search icon">clear</mat-icon>
</button>
</div>
</div>
<mat-select-trigger title="{{displayString|translate}}">
{{ displayString | translate }}
</mat-select-trigger>
<cdk-virtual-scroll-viewport [itemSize]="getItemSize()"
[style.height.px]="getViewPortHeight()">
<mat-option *cdkVirtualFor="let option of filteredOptions; let i = index"
[attr.data-optionIndex]="i"
[disabled]="option.disabled" [value]="option.value"
[ngClass]="{'tree-mat-option': isTree}"
title="{{option.displayValue|translate}}"
(onSelectionChange)="onSelectionChange($event)">
<div *ngIf="!isTree">{{ option.displayValue | translate }}</div>
<div *ngIf="!!isTree" class="tree-multiline-mat-option">
<div mat-line>{{ onDisplayTreeData(option.displayValue, true) }}</div>
<p mat-line>{{ onDisplayTreeData(option.displayValue, false) }}</p>
</div>
</mat-option>
</cdk-virtual-scroll-viewport>
<ng-container *ngIf="multiple">
<ng-container *ngFor="let option of selectedValue; let i = index">
<mat-option class="selected-options" [value]="option" *ngIf="i===0">
{{ option }}
</mat-option>
</ng-container>
</ng-container>
<ng-container *ngIf="!multiple">
<mat-option class="selected-options" *ngIf="!!selectedValue"
[value]="selectedValue">{{ selectedValue }}
</mat-option>
</ng-container>
</mat-select>
<mat-icon matSuffix>expand_more</mat-icon>
<mat-hint *ngIf="!NsValidator.invalid(formControl)">{{ hint | translate }}</mat-hint>
<mat-hint style="color: red" *ngIf="NsValidator.invalid(formControl)">
{{ NsValidator.getErrorMessage(formControl, errorMessages) | translate }}
</mat-hint>
</mat-form-field>
</div>
`,
}]
}], ctorParameters: () => [{ type: i1.TranslateService }, { type: i0.Injector }, { type: i1$2.NgControl, decorators: [{
type: Self
}, {
type: Optional
}] }], propDecorators: { placeholder: [{
type: Input
}], label: [{
type: Input
}], hint: [{
type: Input
}], value: [{
type: Input
}], options: [{
type: Input
}], disabled: [{
type: Input
}], errorMessages: [{
type: Input
}], multiple: [{
type: Input
}], required: [{
type: Input
}], isTree: [{
type: Input
}], treeSymbol: [{
type: Input
}], sizeOfItemsInListByPixels: [{
type: Input
}], isLabelOutside: [{
type: Input
}], isFloatLabel: [{
type: Input
}], percentOfLabelOutside: [{
type: Input
}], selectionChange: [{
type: Output
}], selectedOptionDataChange: [{
type: Output
}], isFormControl: [{
type: Input
}], searchInputRef: [{
type: ViewChild,
args: ['searchInput']
}], cdkVirtualScrollViewPort: [{
type: ViewChild,
args: [CdkVirtualScrollViewport, { static: false }]
}] } });
class CvaLiveSearchingComponent {
injector;
label = '';
placeholder = '';
hint = '';
required = false;
disabled = false;
readonly = false;
errorMessages = new Map();
isLabelOutside = false;
isFloatLabel = true;
percentOfLabelOutside = 25;
suffixFontAwesomeClass = '';
displayKey = '';
mappingConfig = {};
searchFn;
onChange = new EventEmitter();
// Chỉ bằng false khi trong NsSmartTable thôi nhé @@
isFormControl = true;
row;
columnDef;
control = undefined;
textControl = new FormControl('');
filteredOptions = [];
selected;
loading = false;
searchSub;
constructor(injector, ngControl) {
this.injector = injector;
if (ngControl) {
// Hành động này thay cho provide: NG_VALUE_ACCESSOR và gắn ControlValueAccessor này vào parent FormControl
ngControl.valueAccessor = this;
}
}
get NsValidator() {
return ValidatorService;
}
ngOnInit() {
this.callValidator();
this.textValueChangeSubscribe();
if (!this.isFormControl && !!this.searchFn && this.row && this.columnDef) {
this.writeValue(this.row[this.columnDef]);
}
}
callValidator() {
const ngControl = this.injector.get(NgControl);
// Nếu parent FormControl khởi tạo xong và formControl chưa có giá trị lưu
if (ngControl && !this.control) {
// Nếu là NsSmartTable thì phải tự new FormControl còn không thì cứ hóng parent FormControl về ^^
if (this.isFormControl) {
this.control = ngControl.control ? ngControl.control : undefined;
}
else {
this.control = new FormControl();
}
// Hành động này gắn validator vào this.formControl
// - Nếu this.formControl là parent FormControl thì sẽ show error lên FormGroup
// - Nếu this.formControl là new FormControl thì sẽ quét QueryList để check {errors}
if (this.control) {
if (this.control.validator) {
this.control.setValidators([...ValidatorService.generateNsAutocompleteValidators({
required: this.required,
}), this.control.validator]);
}
else {
this.control.setValidators([...ValidatorService.generateNsAutocompleteValidators({
required: this.required,
})]);
}
}
}
if (this.control) {
// Nếu this.formControl thuộc NsSmartTable thì setValue lại
if (!this.isFormControl) {
this.control.setValue(this.selected);
}
// Nếu là parent FormControl rồi thì kệ
this.control.updateValueAndValidity();
}
}
propagateChange = (_) => {
/*NON-EMPTY FOR COMPILE*/
};
/**
* Set the function to be called
* when the formControl receives a change event.
*/
registerOnChange(fn) {
this.propagateChange = fn;
}
/**
* Set the function to be called
* when the formControl receives a touch event.
*/
registerOnTouched() {
/*NON-EMPTY FOR COMPILE*/
}
/**
* Write a new value to the element.
*/
writeValue(obj) {
if (!obj || typeof obj !== 'string') {
this.selected = {};
this.filteredOptions.length = 0;
this.filteredOptions = [];
this.textControl.setValue('', { emitEvent: false });
this.updateRowOrFormGroup();
return;
}
const matched = this.filteredOptions.find(opt => {
return JSON.stringify(opt[this.displayKey] ?? '') === JSON.stringify(obj ?? '');
});
if (!matched) {
if (!this.searchFn) {
return;
}
// Khi textValueChange chưa chạy không tìm thấy
this.searchFn(obj).subscribe(values => {
if (values && values.length > 0) {
this.filteredOptions = [...values];
this.onOptionSelect(obj);
}
});
return;
}
this.selected = matched;
this.textControl.setValue(matched[this.displayKey], { emitEvent: false });
this.updateRowOrFormGroup();
}
onOptionSelect(displayValue) {
this.searchSub?.unsubscribe();
this.writeValue(displayValue);
setTimeout(() => this.textValueChangeSubscribe(), 100);
}
textValueChangeSubscribe() {
this.searchSub = this.textControl.valueChanges.pipe(debounceTime(300), distinctUntilChanged(), filter(text => typeof text === 'string' && text.trim().length > 0), tap(() => this.loading = true), switchMap((text) => {
if (typeof text !== 'string' || !text || !text.trim())
return of([]);
return this.searchFn ? this.searchFn(text) : of([]);
}), tap(() => this.loading = false)).subscribe((data) => {
this.filteredOptions.length = 0;
this.filteredOptions = [];
if (!!this.selected && !!this.selected[this.displayKey]) {
this.filteredOptions.push(this.selected);
this.filteredOptions.push(...data.filter((x) => x[this.displayKey] !== this.selected[this.displayKey]));
}
else {
this.filteredOptions.push(...data);
}
});
}
updateRowOrFormGroup() {
if (!this.isFormControl && this.row) {
for (const targetKey in this.mappingConfig) {
const sourceKey = this.mappingConfig[targetKey];
this.row[targetKey] = this.selected[sourceKey];
}
}
if (this.isFormControl && this.control?.parent) {
for (const targetKey in this.mappingConfig) {
const sourceKey = this.mappingConfig[targetKey];
const formControl = this.control.parent.get(targetKey);
if (formControl)
formControl.setValue(this.selected[sourceKey]);
}
}
this.propagateChange(this.selected[this.displayKey]);
this.onChange.emit(this.selected[this.displayKey]);
}
onClear() {
this.writeValue(null);
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: CvaLiveSearchingComponent, deps: [{ token: i0.Injector }, { token: i1$2.NgControl, optional: true, self: true }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.5", type: CvaLiveSearchingComponent, isStandalone: false, selector: "cva-live-searching", inputs: { label: "label", placeholder: "placeholder", hint: "hint", required: "required", disabled: "disabled", readonly: "readonly", errorMessages: "errorMessages", isLabelOutside: "isLabelOutside", isFloatLabel: "isFloatLabel", percentOfLabelOutside: "percentOfLabelOutside", suffixFontAwesomeClass: "suffixFontAwesomeClass", displayKey: "displayKey", mappingConfig: "mappingConfig", searchFn: "searchFn", isFormControl: "isFormControl", row: "row", columnDef: "columnDef" }, outputs: { onChange: "onChange" }, ngImport: i0, template: `
<div class="cva-live-searching"
[ngClass]="{'labelOutside': !!isLabelOutside,
'float_label': !!isFloatLabel && !isLabelOutside}"
fxLayout="row" fxLayout.lt-sm="row wrap">
<mat-label *ngIf="isLabelOutside" class="label_width"
fxLayout="column" fxFlex="auto" fxFlex.lt-md="100%">
<div class="label">
<div>
{{ (label ? label : placeholder) | translate }}<span
class="required-label-outside">{{ !!required ? '*' : '' }}</span>
</div>
</div>
</mat-label>
<mat-form-field appearance="outline" [floatLabel]="!!isFloatLabel ? 'always' : 'auto'"
[hideRequiredMarker]="!isFloatLabel"
fxLayout="column" fxFlex="auto" fxFlex.lt-md="100%">
<mat-label *ngIf="!isLabelOutside && !!isFloatLabel">
{{ (label ? label : placeholder) | translate }}
</mat-label>
<input type="text"
matInput
[required]="required"
[disabled]="disabled"
placeholder="{{placeholder|translate}}"
[formControl]="textControl"
[matAutocomplete]="auto"
readonly="{{readonly}}" />
<button mat-icon-button color="warn" class="btnClear" matSuffix (click)="onClear()" *ngIf="!loading">
<mat-icon>clear</mat-icon>
</button>
<mat-spinner diameter="20" matSuffix *ngIf="loading"></mat-spinner>
<mat-autocomplete #auto="matAutocomplete" autoActiveFirstOption
(optionSelected)="onOptionSelect($event.option.value)">
<mat-option *ngFor="let option of filteredOptions" [value]="option[displayKey]">
{{ option[displayKey] }}
</mat-option>
</mat-autocomplete>
<i *ngIf="!!suffixFontAwesomeClass" class="input-suffix {{suffixFontAwesomeClass}}" matSuffix></i>
<mat-hint align="start" *ngIf="!NsValidator.invalid(control)">{{ hint | translate }}</mat-hint>
<mat-hint style="color: red" align="start" *ngIf="NsValidator.invalid(control)">
{{ NsValidator.getErrorMessageV1(control, errorMessages).msg | translate: NsValidator.getErrorMessageV1(control, errorMessages).params }}
</mat-hint>
</mat-form-field>
</div>
`, isInline: true, dependencies: [{ kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: i3$2.MatAutocomplete, selector: "mat-autocomplete", inputs: ["aria-label", "aria-labelledby", "displayWith", "autoActiveFirstOption", "autoSelectActiveOption", "requireSelection", "panelWidth", "disableRipple", "class", "hideSingleSelectionIndicator"], outputs: ["optionSelected", "opened", "closed", "optionActivated"], exportAs: ["matAutocomplete"] }, { kind: "component", type: i4$2.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "directive", type: i3$2.MatAutocompleteTrigger, selector: "input[matAutocomplete], textarea[matAutocomplete]", inputs: ["matAutocomplete", "matAutocompletePosition", "matAutocompleteConnectedTo", "autocomplete", "matAutocompleteDisabled"], exportAs: ["matAutocompleteTrigger"] }, { kind: "component", type: i3.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "component", type: i6.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i6.MatLabel, selector: "mat-label" }, { kind: "directive", type: i6.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "directive", type: i6.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "component", type: i7.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: i4.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "component", type: i9$2.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "directive", type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { kind: "directive", type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { kind: "directive", type: i9.DefaultClassDirective, selector: " [ngClass], [ngClass.xs], [ngClass.sm], [ngClass.md], [ngClass.lg], [ngClass.xl], [ngClass.lt-sm], [ngClass.lt-md], [ngClass.lt-lg], [ngClass.lt-xl], [ngClass.gt-xs], [ngClass.gt-sm], [ngClass.gt-md], [ngClass.gt-lg]", inputs: ["ngClass", "ngClass.xs", "ngClass.sm", "ngClass.md", "ngClass.lg", "ngClass.xl", "ngClass.lt-sm", "ngClass.lt-md", "ngClass.lt-lg", "ngClass.lt-xl", "ngClass.gt-xs", "ngClass.gt-sm", "ngClass.gt-md", "ngClass.gt-lg"] }, { kind: "pipe", type: i1.TranslatePipe, name: "translate" }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: CvaLiveSearchingComponent, decorators: [{
type: Component,
args: [{
selector: 'cva-live-searching',
standalone: false,
template: `
<div class="cva-live-searching"
[ngClass]="{'labelOutside': !!isLabelOutside,
'float_label': !!isFloatLabel && !isLabelOutside}"
fxLayout="row" fxLayout.lt-sm="row wrap">
<mat-label *ngIf="isLabelOutside" class="label_width"
fxLayout="column" fxFlex="auto" fxFlex.lt-md="100%">
<div class="label">
<div>
{{ (label ? label : placeholder) | translate }}<span
class="required-label-outside">{{ !!required ? '*' : '' }}</span>
</div>
</div>
</mat-label>
<mat-form-field appearance="outline" [floatLabel]="!!isFloatLabel ? 'always' : 'auto'"
[hideRequiredMarker]="!isFloatLabel"
fxLayout="column" fxFlex="auto" fxFlex.lt-md="100%">
<mat-label *ngIf="!isLabelOutside && !!isFloatLabel">
{{ (label ? label : placeholder) | translate }}
</mat-label>
<input type="text"
matInput
[required]="required"
[disabled]="disabled"
placeholder="{{placeholder|translate}}"
[formControl]="textControl"
[matAutocomplete]="auto"
readonly="{{readonly}}" />
<button mat-icon-button color="warn" class="btnClear" matSuffix (click)="onClear()" *ngIf="!loading">
<mat-icon>clear</mat-icon>
</button>
<mat-spinner diameter="20" matSuffix *ngIf="loading"></mat-spinner>
<mat-autocomplete #auto="matAutocomplete" autoActiveFirstOption
(optionSelected)="onOptionSelect($event.option.value)">
<mat-option *ngFor="let option of filteredOptions" [value]="option[displayKey]">
{{ option[displayKey] }}
</mat-option>
</mat-autocomplete>
<i *ngIf="!!suffixFontAwesomeClass" class="input-suffix {{suffixFontAwesomeClass}}" matSuffix></i>
<mat-hint align="start" *ngIf="!NsValidator.invalid(control)">{{ hint | translate }}</mat-hint>
<mat-hint style="color: red" align="start" *ngIf="NsValidator.invalid(control)">
{{ NsValidator.getErrorMessageV1(control, errorMessages).msg | translate: NsValidator.getErrorMessageV1(control, errorMessages).params }}
</mat-hint>
</mat-form-field>
</div>
`,
}]
}], ctorParameters: () => [{ type: i0.Injector }, { type: i1$2.NgControl, decorators: [{
type: Self
}, {
type: Optional
}] }], propDecorators: { label: [{
type: Input
}], placeholder: [{
type: Input
}], hint: [{
type: Input
}], required: [{
type: Input
}], disabled: [{
type: Input
}], readonly: [{
type: Input
}], errorMessages: [{
type: Input
}], isLabelOutside: [{
type: Input
}], isFloatLabel: [{
type: Input
}], percentOfLabelOutside: [{
type: Input
}], suffixFontAwesomeClass: [{
type: Input
}], displayKey: [{
type: Input
}], mappingConfig: [{
type: Input
}], searchFn: [{
type: Input
}], onChange: [{
type: Output
}], isFormControl: [{
type: Input
}], row: [{
type: Input
}], columnDef: [{
type: Input
}] } });
class CvaSmartTableComponent {
ref;
config;
injector;
moduleName = '';
columns = [];
buttons = [];
value = [];
minRow = 0;
maxRow = 9999;
errorMessages = new Map();
isFormControl = true;
isSticky = false;
isStickyHeader = false;
isStickyFooter = false;
clickAction = new EventEmitter();
onChange = new EventEmitter();
matTable;
isExpandRowTable = false;
expandRowProperty = '';
$displayedColumns = [];
$displayedFooters = [];
datasource = new MatTableDataSource([]);
formControl;
selectAllChecked = false;
buttonColspan = 0;
constructor(ref, config, injector, ngControl) {
this.ref = ref;
this.config = config;
this.injector = injector;
if (ngControl) {
ngControl.valueAccessor = this;
}
}
get AlignEnum() {
return AlignEnum;
}
get IconTypes() {
return IconTypeEnum;
}
get TableService() {
return TableService;
}
get displayedColumns() {
if (!this.$displayedColumns || this.$displayedColumns.length <= 0) {
this.$displayedColumns = this.columns.map((c) => c.columnDef);
if (this.buttons) {
this.$displayedColumns = this.$displayedColumns.concat(this.buttons.map((b) => b.columnDef));
}
}
return this.$displayedColumns;
}
get displayedFooters() {
if (!this.$displayedFooters || this.$displayedFooters.length <= 0) {
for (const column of this.columns) {
if (!!column.footers) {
for (let i = 0; i < column.footers.length; i++) {
if (!this.$displayedFooters[i]) {
this.$displayedFooters[i] = [];
}
this.$displayedFooters[i] = this.$displayedFooters[i].concat([i + '-' + column.columnDef]);
}
}
}
}
return this.$displayedFooters;
}
get ColumnTypes() {
return ColumnTypeEnum;
}
propagateChange = (_) => {
/*NON-EMPTY FOR COMPILE*/
};
writeValue(obj) {
if (obj) {
this.value = obj;
if (this.isExpandRowTable && this.datasource.data !== this.value) {
this.datasource = new MatTableDataSource(this.value);
let parentRowIndex = 0;
for (let i = 0; i < this.datasource.data.length; i++) {
const row = this.datasource.data[i];
if (!row.isChildRow) {
this.expandRow(i, row, parentRowIndex);
parentRowIndex = (++parentRowIndex) % 2;
}
}
}
else {
this.datasource = new MatTableDataSource(this.value);
}
this.toggleSelect(null);
this.callValidator();
this.propagateChange(this.isExpandRowTable ? this.getParentRowData() : this.value);
this.onChange.emit();
}
}
getParentRowData() {
return this.value.filter((row) => {
return !row.isChildRow;
});
}
registerOnChange(fn) {
this.propagateChange = fn;
}
registerOnTouched() {
/*NON-EMPTY FOR COMPILE*/
}
ngOnChanges() {
this.writeValue(this.value);
}
ngOnInit() {
this.callValidator();
}
ngAfterContentChecked() {
this.getHeaderButtonColspan();
this.ref.detectChanges();
}
/*
Nếu sử dụng expandTableRow khi xử lý sự kiện bên ngoài component không sử dụng index bên trong base, set index lại bằng indexOf
*/
onClick(action, result, index) {
const buttonClickEvent = new ButtonClickEvent(action, result, index);
this.clickAction.emit(buttonClickEvent);
}
onCellValueChange(result, column, $event) {
result[column.columnDef] = $event;
if (column.onCellValueChange) {
column.onCellValueChange(result);
}
this.callValidator();
this.onChange.emit();
}
toggleSelectAll(val, col) {
if (this.value) {
this.value.forEach(v => {
v.checked = val.checked;
});
}
if (col.onHeaderCellValueChange) {
col.onHeaderCellValueChange(val.checked);
}
}
toggleSelect(val, result, column) {
let count = 0;
if (this.value && this.value.length > 0) {
this.value.forEach(v => {
if (v.checked) {
count++;
}
});
this.selectAllChecked = count === this.value.length;
}
else {
this.selectAllChecked = false;
}
if (column) {
this.onCellValueChange(result, column, val?.checked);
}
}
onDisplayHeaderCell(column) {
return column.isShowHeader ? column.isShowHeader : false;
}
onDisplayFooter(footer, dataTable) {
return typeof (footer.display) === 'function' ? footer.display(dataTable) : !!footer.display;
}
// //Cái khúc này về sau mà có cái loại validate nào mà ngoài thì mới enable validate cột sau
// validate(control: AbstractControl): ValidationErrors | null {
// let valid = null;
//
// if (this.value) {
// for (const row of this.value) {
// for (const column of this.columns) {
// if (column.validate) {
// valid = column.validate(row);
// if (valid) {
// break;
// }
// }
// }
// if (valid) {
// break;
// }
// }
// }
// return valid;
// }
callValidator() {
const ngControl = this.injector.get(NgControl);
if (ngControl && !this.formControl) {
if (this.isFormControl) {
this.formControl = ngControl.control ? ngControl.control : undefined;
}
else {
this.formControl = new FormControl();
}
if (this.formControl) {
this.formControl.setValidators(ValidatorService.generateNsSmartTableValidators({
columns: this.columns,
minRow: this.minRow,
maxRow: this.maxRow,
}));
}
}
if (this.formControl) {
if (!this.isFormControl) {
this.formControl.setValue(this.value);
}
this.formControl.updateValueAndValidity();
}
}
getRequired(column) {
return typeof (column.isRequired) === 'function' ? column.isRequired() : column.isRequired;
}
getIsDecimal(column) {
return column.isDecimal ? typeof (column.isDecimal) === 'boolean' ? column.isDecimal : column.isDecimal() : false;
}
getErrorMessageMap(column) {
return column.errorMessage ? column.errorMessage : new Map();
}
expandRow(i, row, parentRowClassIndex) {
// do not add more rows if the click was on a child row
if (row.isChildRow) {
return;
}
// default not expand
// if (row.expanded) {
// // remove the flag
// row.expanded = false;
//
// // remove the child rows
// let childrenDetected = false;
// const length = this.datasource.data.length;
// for (let index = 0; index < length; index++) {
// if (childrenDetected && !this.datasource.data[index].isChildRow) {
// break;
// }
//
// if (index > i && this.datasource.data[index].isChildRow) {
// this.datasource.data.splice(index, 1);
// index--;
// childrenDetected = true;
// }
// }
//
// this.matTable?.renderRows();
// return;
// }
// set expanded to true so we don't expand this row again
row.expanded = true;
row.parentRowClassIndex = parentRowClassIndex;
const itemsToAdd = row[this.expandRowProperty];
// mark as child rows
itemsToAdd.forEach(item => {
item.isChildRow = true;
item.parentRowClassIndex = parentRowClassIndex;
});
// add rows including header row
itemsToAdd.reverse();
itemsToAdd.forEach(x => {
this.datasource.data.splice(i + 1, 0, x);
});
// rerender table
this.matTable?.renderRows();
}
getCounterImputAlign(column) {
return column.align ? column.align : AlignEnum.RIGHT;
}
getHeaderButtonColspan() {
this.buttonColspan = TableService.getHeaderButtonColspan(this.buttons, this.datasource.data);
return this.buttonColspan;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: CvaSmartTableComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: InjectTokenNextSolutionsConfig }, { token: i0.Injector }, { token: i1$2.NgControl, optional: true, self: true }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.5", type: CvaSmartTableComponent, isStandalone: false, selector: "cva-smart-table", inputs: { moduleName: "moduleName", columns: "columns", buttons: "buttons", value: "value", minRow: "minRow", maxRow: "maxRow", errorMessages: "errorMessages", isFormControl: "isFormControl", isSticky: "isSticky", isStickyHeader: "isStickyHeader", isStickyFooter: "isStickyFooter", isExpandRowTable: "isExpandRowTable", expandRowProperty: "expandRowProperty" }, outputs: { clickAction: "clickAction", onChange: "onChange" }, viewQueries: [{ propertyName: "matTable", first: true, predicate: ["matTable"], descendants: true }], usesOnChanges: true, ngImport: i0, template: `
<div class="table-responsive"
[ngClass]="{'fixed_header': isSticky||isStickyHeader, 'fixed_footer': isSticky||isStickyFooter}">
<table mat-table [dataSource]="datasource" #matTable class="mat-elevation-z8 cva-smart-table">
<ng-container *ngFor="let column of columns" matColumnDef="{{column.columnDef}}">
<ng-container *matHeaderCellDef>
<th mat-header-cell class="{{TableService.getColumnHeaderClassName(column)}}"
*ngIf="onDisplayHeaderCell(column)">
<!-- *ngIf="getColumnType(column, result)!==ColumnTypes.CHECKBOX"-->
<div [ngClass]="{'break-word-style-view': column.hasWordBreakStyle}"
fxLayout="row"
[fxLayoutAlign]="column.alignHeader ? column.alignHeader : TableService.alignCellContent(column)">
<mat-checkbox
*ngIf="TableService.getColumnType(column, null)===ColumnTypes.CHECKBOX && !column.isNotShowHeaderCheckbox"
color="primary" class="box-select-all margin-right-5" [(ngModel)]="selectAllChecked"
(change)="toggleSelectAll($event, column)">
</mat-checkbox>
{{ TableService.displayHeaderName(column, moduleName) | translate }}<span
style="color: red">{{ getRequired(column) ? '*' : '' }}</span>
</div>
</th>
</ng-container>
<ng-container *matCellDef="let result; let i = index">
<td mat-cell [ngClass]="TableService.getColumnClassName(column,result)"
*ngIf="TableService.onDisplayCell(column, result)"
[ngSwitch]="TableService.getColumnType(column, result)">
<div title="{{column.title(result)}}"
*ngSwitchCase="ColumnTypes.VIEW"
class="viewData {{TableService.getColumnClassName(column,result)}}"
fxLayout="row" [fxLayoutAlign]="TableService.alignCellContent(column)">
{{ column.cell(result) }}
</div>
<div class="link viewData"
[ngClass]="{'break-word-style-view': column.hasWordBreakStyle}"
*ngSwitchCase="ColumnTypes.LINK"
fxLayout="row" [fxLayoutAlign]="TableService.alignCellContent(column)"
title="{{column.title(result)}}">
<a [routerLink]="[column.link(result)]">{{ column.cell(result) }}</a>
</div>
<div class="img-view viewData {{TableService.getColumnClassName(column,result)}}"
[ngClass]="{'break-word-style-view': column.hasWordBreakStyle}"
*ngSwitchCase="ColumnTypes.IMG"
fxLayout="row" [fxLayoutAlign]="TableService.alignCellContent(column)"
title="{{column.title(result)}}">
<img [src]="column.cell(result) | secure | async"
#imgRef
(error)="TableService.onErrorImgEvent(imgRef, config.NO_IMAGE_AVAILABLE)" alt="" />
</div>
<div class="img-view viewData {{TableService.getColumnClassName(column,result)}}"
[ngClass]="{'break-word-style-view': column.hasWordBreakStyle}"
*ngSwitchCase="ColumnTypes.IMG_NO_SECURE"
fxLayout="row" [fxLayoutAlign]="TableService.alignCellContent(column)"
title="{{column.title(result)}}">
<img [src]="column.cell(result)"
#imgRef
(error)="TableService.onErrorImgEvent(imgRef, config.NO_IMAGE_AVAILABLE)" alt="" />
</div>
<div *ngSwitchCase="ColumnTypes.BASE64"
class="viewData img-view base64 {{TableService.getColumnClassName(column,result)}}"
fxLayout="row" [fxLayoutAlign]="TableService.alignCellContent(column)"
title="{{column.title(result)}}">
<img [src]="'data:image/png;base64,'+column.cell(result)"
#base64ImgRef
(error)="TableService.onErrorImgEvent(base64ImgRef, config.NO_IMAGE_AVAILABLE)" alt="" />
</div>
<ng-container *ngSwitchCase="ColumnTypes.BUTTON">
<div *ngIf="!!column.button"
class="{{TableService.getColumnClassName(column, result)}}"
fxLayout="row" [fxLayoutAlign]="TableService.alignCellContent(column)"
(click)="$event.stopPropagation()">
<button mat-icon-button
color="{{column.button.color}}"
[ngClass]="column.button.className"
(click)="onClick(column.button.click, result, i)"
disabled="{{column.button.disabled ? column.button.disabled(result) : false}}"
matTooltip="{{(column.button.title ? column.button.title : '') | translate}}"
[ngSwitch]="TableService.getIconType(column.button)">
<mat-icon *ngSwitchCase="IconTypes.MATERIAL_ICON">{{ column.button.icon }}</mat-icon>
<i *ngSwitchCase="IconTypes.FONT_AWESOME" class="{{column.button.icon}}"></i>
</button>
</div>
</ng-container>
<cva-counter-input *ngSwitchCase="ColumnTypes.INPUT_COUNTER"
class="inputNumber" #nsCounterInput
[isFormControl]="false"
[alignNumber]="getCounterImputAlign(column)"
[disabled]="column.disabled ? column.disabled(result) : false"
[value]="result[column.columnDef]"
[required]="getRequired(column)"
[errorMessages]="getErrorMessageMap(column)"
[isDecimal]="getIsDecimal(column)"
[min]="column.min ? column.min(result) : null"
[max]="column.max ? column.max(result) : null"
(onChange)="onCellValueChange(result, column, $event);">
</cva-counter-input>
<cva-input *ngSwitchCase="ColumnTypes.INPUT"
[isFormControl]="false"
[disabled]="column.disabled ? column.disabled(result) : false"
[text]="result[column.columnDef]"
[minLength]="column.min ? column.min(result) : undefined"
[maxLength]="column.max ? column.max(result) : undefined"
[required]="getRequired(column)"
[errorMessages]="getErrorMessageMap(column)"
(onChange)="onCellValueChange(result, column, $event);">
</cva-input>
<cva-date-picker *ngSwitchCase="ColumnTypes.DATE_PICKER"
[value]="result[column.columnDef]"
[isFormControl]="false"
[minDate]="column.min ? column.min(result) : null"
[maxDate]="column.max ? column.max(result) : null"
[required]="getRequired(column)"
[disabled]="column.disabled ? column.disabled(result) : false"
[errorMessages]="getErrorMessageMap(column)"
(onChange)="onCellValueChange(result, column, $event);">
</cva-date-picker>
<cva-multi-select-autocomplete [isFormControl]="false"
*ngSwitchCase="ColumnTypes.MULTI_SELECT_AUTOCOMPLETE"
class="multiSelectAutocomplete"
[isTree]="column.isTree"
[value]="result[column.columnDef]"
[errorMessages]="getErrorMessageMap(column)"
[required]="getRequired(column)"
[disabled]="column.disabled ? column.disabled(result) : false"
[multiple]="column.isMultipleSelect"
[options]="column.optionValues(result)"
(selectionChange)="onCellValueChange(result, column, $event);">
</cva-multi-select-autocomplete>
<div class="checkbox-cell"
fxLayout="row"
[fxLayoutAlign]="TableService.alignCellContent(column)"
*ngSwitchCase="ColumnTypes.CHECKBOX">
<mat-checkbox [(ngModel)]="result[column.columnDef]" color="primary"
*ngIf="column.display ? column.display(result) : true"
[disabled]="column.disabled ? column.disabled(result) : false"
(change)="toggleSelect($event,result, column)">
</mat-checkbox>
</div>
<cva-live-searching *ngSwitchCase="ColumnTypes.LIVE_SEARCHING"
[isFormControl]="false" [required]="getRequired(column)"
[row]="result" [columnDef]="column.columnDef"
[searchFn]="column.searchFn"
[mappingConfig]="column.mappingConfig"
[displayKey]="column.displayKey"
[errorMessages]="getErrorMessageMap(column)"
(onChange)="onCellValueChange(result, column, $event)">
</cva-live-searching>
</td>
</ng-container>
</ng-container>
<ng-container *ngFor="let button of buttons; let i = index" matColumnDef="{{button.columnDef}}">
<ng-container *matHeaderCellDef="let header">
<th mat-header-cell
[ngClass]="button.className"
*ngIf="TableService.onDisplayButtonHeaderCell(buttons, button, header, i) && !!buttonColspan"
(click)="$event.stopPropagation()"
[attr.colspan]="buttonColspan">
<!-- [fxFlex]="getHeaderButtonWidth(i) + 'px' "-->
<ng-container *ngIf="TableService.getButtonHeader(button) as btnHeader">
<button mat-icon-button
class="{{button.className}}"
color="{{$any(btnHeader).color}}"
(click)="onClick($any(btnHeader).click, null, null)"
[disabled]="(btnHeader && $any(btnHeader).disabled) ? $any(btnHeader).disabled(header) : false"
*ngIf="(btnHeader && btnHeader.display) ? btnHeader.display(header) : false"
matTooltip="{{((btnHeader && $any(btnHeader).title) ? $any(btnHeader).title : '') | translate}}"
[ngSwitch]="TableService.getIconType($any(btnHeader))">
<mat-icon *ngSwitchCase="IconTypes.MATERIAL_ICON">{{ $any(btnHeader).icon }}</mat-icon>
<i *ngSwitchCase="IconTypes.FONT_AWESOME" class="{{$any(btnHeader).icon}}"></i>
</button>
</ng-container>
<ng-container *ngIf="TableService.getButtonHeaderString(button) as btnHeader">
<div title="{{$any(btnHeader) | translate}}"
class="viewData"
fxLayout="row"
fxLayoutAlign="{{button.alignHeader ? button.alignHeader : AlignEnum.LEFT}} center">
{{ $any(btnHeader) | translate }}
</div>
</ng-container>
</th>
</ng-container>
<ng-container *matCellDef="let cell; let i = index">
<td mat-cell [ngClass]="button.className"
*ngIf="TableService.onDisplayButtonCell(button, cell)"
(click)="$event.stopPropagation()">
<button mat-icon-button
color="{{button.color}}"
[ngClass]="button.className"
(click)="onClick(button.click, cell, i)"
disabled="{{button.disabled ? button.disabled(cell) : false}}"
matTooltip="{{(button.title ? button.title : '') | translate}}"
[ngSwitch]="TableService.getIconType(button)">
<mat-icon *ngSwitchCase="IconTypes.MATERIAL_ICON">{{ button.icon }}</mat-icon>
<i *ngSwitchCase="IconTypes.FONT_AWESOME" class="{{button.icon}}"></i>
</button>
</td>
</ng-container>
</ng-container>
<ng-container *ngFor="let column of columns">
<ng-container *ngFor="let footer of column.footers; let i = index"
matColumnDef="{{i}}-{{column.columnDef}}">
<ng-container *matFooterCellDef>
<td mat-footer-cell *ngIf="onDisplayFooter(footer, datasource.data)"
[attr.colspan]="TableService.getColspan(footer, datasource.data)"
class="{{TableService.getColumnClassName(column,datasource.data)}} {{TableService.getColumnClassName(column.footer,datasource.data)}}">
<div title="{{footer.title(datasource.data)}}"
class="viewData {{TableService.getColumnClassName(column,datasource.data)}}"
fxLayout="row"
[fxLayoutAlign]="footer.align ? footer.align : AlignEnum.LEFT">
{{ footer.cell(datasource.data) }}
</div>
</td>
</ng-container>
</ng-container>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: isSticky||isStickyHeader"></tr>
<tr mat-row *matRowDef="let result; columns: displayedColumns;" class="{{result.className}}"
[ngClass]="{'childRow0': !!result.isChildRow && result.parentRowClassIndex === 0,
'parentRow0': !result.isChildRow && result.parentRowClassIndex === 0,
'childRow1': !!result.isChildRow && result.parentRowClassIndex === 1,
'parentRow1': !result.isChildRow && result.parentRowClassIndex === 1}"
></tr>
<ng-container *ngFor="let df of displayedFooters">
<tr mat-footer-row *matFooterRowDef="df; sticky: isSticky||isStickyFooter"></tr>
</ng-container>
</table>
</div>
`, isInline: true, dependencies: [{ kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i2.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i3.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "component", type: i4$1.MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "component", type: i5.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i5.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i5.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i5.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i5.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i5.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i5.MatFooterCellDef, selector: "[matFooterCellDef]" }, { kind: "directive", type: i5.MatFooterRowDef, selector: "[matFooterRowDef]", inputs: ["matFooterRowDef", "matFooterRowDefSticky"] }, { kind: "directive", type: i5.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i5.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "directive", type: i5.MatFooterCell, selector: "mat-footer-cell, td[mat-footer-cell]" }, { kind: "component", type: i5.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i5.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "component", type: i5.MatFooterRow, selector: "mat-footer-row, tr[mat-footer-row]", exportAs: ["matFooterRow"] }, { kind: "component", type: i7.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: i8$1.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "directive", type: i1$4.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { kind: "directive", type: i8.DefaultLayoutAlignDirective, selector: " [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]", inputs: ["fxLayoutAlign", "fxLayoutAlign.xs", "fxLayoutAlign.sm", "fxLayoutAlign.md", "fxLayoutAlign.lg", "fxLayoutAlign.xl", "fxLayoutAlign.lt-sm", "fxLayoutAlign.lt-md", "fxLayoutAlign.lt-lg", "fxLayoutAlign.lt-xl", "fxLayoutAlign.gt-xs", "fxLayoutAlign.gt-sm", "fxLayoutAlign.gt-md", "fxLayoutAlign.gt-lg"] }, { kind: "directive", type: i9.DefaultClassDirective, selector: " [ngClass], [ngClass.xs], [ngClass.sm], [ngClass.md], [ngClass.lg], [ngClass.xl], [ngClass.lt-sm], [ngClass.lt-md], [ngClass.lt-lg], [ngClass.lt-xl], [ngClass.gt-xs], [ngClass.gt-sm], [ngClass.gt-md], [ngClass.gt-lg]", inputs: ["ngClass", "ngClass.xs", "ngClass.sm", "ngClass.md", "ngClass.lg", "ngClass.xl", "ngClass.lt-sm", "ngClass.lt-md", "ngClass.lt-lg", "ngClass.lt-xl", "ngClass.gt-xs", "ngClass.gt-sm", "ngClass.gt-md", "ngClass.gt-lg"] }, { kind: "component", type: CvaInputComponent, selector: "cva-input", inputs: ["label", "name", "placeholder", "hint", "required", "disabled", "text", "type", "pattern", "readonly", "errorMessages", "multiline", "isLabelOutside", "isFloatLabel", "minLength", "maxLength", "maxLengthDisplay", "percentOfLabelOutside", "suffixFontAwesomeClass", "patternFilter", "isFormControl", "formatFunc"], outputs: ["onChange"] }, { kind: "component", type: CvaCounterInputComponent, selector: "cva-counter-input", inputs: ["label", "placeholder", "suffixText", "hint", "value", "disabled", "required", "errorMessages", "min", "max", "error", "isDecimal", "isLabelOutside", "isFloatLabel", "percentOfLabelOutside", "alignNumber", "isFormControl"], outputs: ["onChange", "onEnter"] }, { kind: "component", type: CvaDatePickerComponent, selector: "cva-date-picker", inputs: ["label", "placeholder", "value", "disabled", "required", "minDate", "maxDate", "errorMessages", "isLabelOutside", "isFloatLabel", "percentOfLabelOutside", "isFormControl"], outputs: ["onChange"] }, { kind: "component", type: CvaMultiSelectAutocomplete, selector: "cva-multi-select-autocomplete", inputs: ["placeholder", "label", "hint", "value", "options", "disabled", "errorMessages", "multiple", "required", "isTree", "treeSymbol", "sizeOfItemsInListByPixels", "isLabelOutside", "isFloatLabel", "percentOfLabelOutside", "isFormControl"], outputs: ["selectionChange", "selectedOptionDataChange"] }, { kind: "component", type: CvaLiveSearchingComponent, selector: "cva-live-searching", inputs: ["label", "placeholder", "hint", "required", "disabled", "readonly", "errorMessages", "isLabelOutside", "isFloatLabel", "percentOfLabelOutside", "suffixFontAwesomeClass", "displayKey", "mappingConfig", "searchFn", "isFormControl", "row", "columnDef"], outputs: ["onChange"] }, { kind: "pipe", type: i2.AsyncPipe, name: "async" }, { kind: "pipe", type: i1.TranslatePipe, name: "translate" }, { kind: "pipe", type: SecureImgPipe, name: "secure" }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: CvaSmartTableComponent, decorators: [{
type: Component,
args: [{
selector: 'cva-smart-table',
standalone: false,
template: `
<div class="table-responsive"
[ngClass]="{'fixed_header': isSticky||isStickyHeader, 'fixed_footer': isSticky||isStickyFooter}">
<table mat-table [dataSource]="datasource" #matTable class="mat-elevation-z8 cva-smart-table">
<ng-container *ngFor="let column of columns" matColumnDef="{{column.columnDef}}">
<ng-container *matHeaderCellDef>
<th mat-header-cell class="{{TableService.getColumnHeaderClassName(column)}}"
*ngIf="onDisplayHeaderCell(column)">
<!-- *ngIf="getColumnType(column, result)!==ColumnTypes.CHECKBOX"-->
<div [ngClass]="{'break-word-style-view': column.hasWordBreakStyle}"
fxLayout="row"
[fxLayoutAlign]="column.alignHeader ? column.alignHeader : TableService.alignCellContent(column)">
<mat-checkbox
*ngIf="TableService.getColumnType(column, null)===ColumnTypes.CHECKBOX && !column.isNotShowHeaderCheckbox"
color="primary" class="box-select-all margin-right-5" [(ngModel)]="selectAllChecked"
(change)="toggleSelectAll($event, column)">
</mat-checkbox>
{{ TableService.displayHeaderName(column, moduleName) | translate }}<span
style="color: red">{{ getRequired(column) ? '*' : '' }}</span>
</div>
</th>
</ng-container>
<ng-container *matCellDef="let result; let i = index">
<td mat-cell [ngClass]="TableService.getColumnClassName(column,result)"
*ngIf="TableService.onDisplayCell(column, result)"
[ngSwitch]="TableService.getColumnType(column, result)">
<div title="{{column.title(result)}}"
*ngSwitchCase="ColumnTypes.VIEW"
class="viewData {{TableService.getColumnClassName(column,result)}}"
fxLayout="row" [fxLayoutAlign]="TableService.alignCellContent(column)">
{{ column.cell(result) }}
</div>
<div class="link viewData"
[ngClass]="{'break-word-style-view': column.hasWordBreakStyle}"
*ngSwitchCase="ColumnTypes.LINK"
fxLayout="row" [fxLayoutAlign]="TableService.alignCellContent(column)"
title="{{column.title(result)}}">
<a [routerLink]="[column.link(result)]">{{ column.cell(result) }}</a>
</div>
<div class="img-view viewData {{TableService.getColumnClassName(column,result)}}"
[ngClass]="{'break-word-style-view': column.hasWordBreakStyle}"
*ngSwitchCase="ColumnTypes.IMG"
fxLayout="row" [fxLayoutAlign]="TableService.alignCellContent(column)"
title="{{column.title(result)}}">
<img [src]="column.cell(result) | secure | async"
#imgRef
(error)="TableService.onErrorImgEvent(imgRef, config.NO_IMAGE_AVAILABLE)" alt="" />
</div>
<div class="img-view viewData {{TableService.getColumnClassName(column,result)}}"
[ngClass]="{'break-word-style-view': column.hasWordBreakStyle}"
*ngSwitchCase="ColumnTypes.IMG_NO_SECURE"
fxLayout="row" [fxLayoutAlign]="TableService.alignCellContent(column)"
title="{{column.title(result)}}">
<img [src]="column.cell(result)"
#imgRef
(error)="TableService.onErrorImgEvent(imgRef, config.NO_IMAGE_AVAILABLE)" alt="" />
</div>
<div *ngSwitchCase="ColumnTypes.BASE64"
class="viewData img-view base64 {{TableService.getColumnClassName(column,result)}}"
fxLayout="row" [fxLayoutAlign]="TableService.alignCellContent(column)"
title="{{column.title(result)}}">
<img [src]="'data:image/png;base64,'+column.cell(result)"
#base64ImgRef
(error)="TableService.onErrorImgEvent(base64ImgRef, config.NO_IMAGE_AVAILABLE)" alt="" />
</div>
<ng-container *ngSwitchCase="ColumnTypes.BUTTON">
<div *ngIf="!!column.button"
class="{{TableService.getColumnClassName(column, result)}}"
fxLayout="row" [fxLayoutAlign]="TableService.alignCellContent(column)"
(click)="$event.stopPropagation()">
<button mat-icon-button
color="{{column.button.color}}"
[ngClass]="column.button.className"
(click)="onClick(column.button.click, result, i)"
disabled="{{column.button.disabled ? column.button.disabled(result) : false}}"
matTooltip="{{(column.button.title ? column.button.title : '') | translate}}"
[ngSwitch]="TableService.getIconType(column.button)">
<mat-icon *ngSwitchCase="IconTypes.MATERIAL_ICON">{{ column.button.icon }}</mat-icon>
<i *ngSwitchCase="IconTypes.FONT_AWESOME" class="{{column.button.icon}}"></i>
</button>
</div>
</ng-container>
<cva-counter-input *ngSwitchCase="ColumnTypes.INPUT_COUNTER"
class="inputNumber" #nsCounterInput
[isFormControl]="false"
[alignNumber]="getCounterImputAlign(column)"
[disabled]="column.disabled ? column.disabled(result) : false"
[value]="result[column.columnDef]"
[required]="getRequired(column)"
[errorMessages]="getErrorMessageMap(column)"
[isDecimal]="getIsDecimal(column)"
[min]="column.min ? column.min(result) : null"
[max]="column.max ? column.max(result) : null"
(onChange)="onCellValueChange(result, column, $event);">
</cva-counter-input>
<cva-input *ngSwitchCase="ColumnTypes.INPUT"
[isFormControl]="false"
[disabled]="column.disabled ? column.disabled(result) : false"
[text]="result[column.columnDef]"
[minLength]="column.min ? column.min(result) : undefined"
[maxLength]="column.max ? column.max(result) : undefined"
[required]="getRequired(column)"
[errorMessages]="getErrorMessageMap(column)"
(onChange)="onCellValueChange(result, column, $event);">
</cva-input>
<cva-date-picker *ngSwitchCase="ColumnTypes.DATE_PICKER"
[value]="result[column.columnDef]"
[isFormControl]="false"
[minDate]="column.min ? column.min(result) : null"
[maxDate]="column.max ? column.max(result) : null"
[required]="getRequired(column)"
[disabled]="column.disabled ? column.disabled(result) : false"
[errorMessages]="getErrorMessageMap(column)"
(onChange)="onCellValueChange(result, column, $event);">
</cva-date-picker>
<cva-multi-select-autocomplete [isFormControl]="false"
*ngSwitchCase="ColumnTypes.MULTI_SELECT_AUTOCOMPLETE"
class="multiSelectAutocomplete"
[isTree]="column.isTree"
[value]="result[column.columnDef]"
[errorMessages]="getErrorMessageMap(column)"
[required]="getRequired(column)"
[disabled]="column.disabled ? column.disabled(result) : false"
[multiple]="column.isMultipleSelect"
[options]="column.optionValues(result)"
(selectionChange)="onCellValueChange(result, column, $event);">
</cva-multi-select-autocomplete>
<div class="checkbox-cell"
fxLayout="row"
[fxLayoutAlign]="TableService.alignCellContent(column)"
*ngSwitchCase="ColumnTypes.CHECKBOX">
<mat-checkbox [(ngModel)]="result[column.columnDef]" color="primary"
*ngIf="column.display ? column.display(result) : true"
[disabled]="column.disabled ? column.disabled(result) : false"
(change)="toggleSelect($event,result, column)">
</mat-checkbox>
</div>
<cva-live-searching *ngSwitchCase="ColumnTypes.LIVE_SEARCHING"
[isFormControl]="false" [required]="getRequired(column)"
[row]="result" [columnDef]="column.columnDef"
[searchFn]="column.searchFn"
[mappingConfig]="column.mappingConfig"
[displayKey]="column.displayKey"
[errorMessages]="getErrorMessageMap(column)"
(onChange)="onCellValueChange(result, column, $event)">
</cva-live-searching>
</td>
</ng-container>
</ng-container>
<ng-container *ngFor="let button of buttons; let i = index" matColumnDef="{{button.columnDef}}">
<ng-container *matHeaderCellDef="let header">
<th mat-header-cell
[ngClass]="button.className"
*ngIf="TableService.onDisplayButtonHeaderCell(buttons, button, header, i) && !!buttonColspan"
(click)="$event.stopPropagation()"
[attr.colspan]="buttonColspan">
<!-- [fxFlex]="getHeaderButtonWidth(i) + 'px' "-->
<ng-container *ngIf="TableService.getButtonHeader(button) as btnHeader">
<button mat-icon-button
class="{{button.className}}"
color="{{$any(btnHeader).color}}"
(click)="onClick($any(btnHeader).click, null, null)"
[disabled]="(btnHeader && $any(btnHeader).disabled) ? $any(btnHeader).disabled(header) : false"
*ngIf="(btnHeader && btnHeader.display) ? btnHeader.display(header) : false"
matTooltip="{{((btnHeader && $any(btnHeader).title) ? $any(btnHeader).title : '') | translate}}"
[ngSwitch]="TableService.getIconType($any(btnHeader))">
<mat-icon *ngSwitchCase="IconTypes.MATERIAL_ICON">{{ $any(btnHeader).icon }}</mat-icon>
<i *ngSwitchCase="IconTypes.FONT_AWESOME" class="{{$any(btnHeader).icon}}"></i>
</button>
</ng-container>
<ng-container *ngIf="TableService.getButtonHeaderString(button) as btnHeader">
<div title="{{$any(btnHeader) | translate}}"
class="viewData"
fxLayout="row"
fxLayoutAlign="{{button.alignHeader ? button.alignHeader : AlignEnum.LEFT}} center">
{{ $any(btnHeader) | translate }}
</div>
</ng-container>
</th>
</ng-container>
<ng-container *matCellDef="let cell; let i = index">
<td mat-cell [ngClass]="button.className"
*ngIf="TableService.onDisplayButtonCell(button, cell)"
(click)="$event.stopPropagation()">
<button mat-icon-button
color="{{button.color}}"
[ngClass]="button.className"
(click)="onClick(button.click, cell, i)"
disabled="{{button.disabled ? button.disabled(cell) : false}}"
matTooltip="{{(button.title ? button.title : '') | translate}}"
[ngSwitch]="TableService.getIconType(button)">
<mat-icon *ngSwitchCase="IconTypes.MATERIAL_ICON">{{ button.icon }}</mat-icon>
<i *ngSwitchCase="IconTypes.FONT_AWESOME" class="{{button.icon}}"></i>
</button>
</td>
</ng-container>
</ng-container>
<ng-container *ngFor="let column of columns">
<ng-container *ngFor="let footer of column.footers; let i = index"
matColumnDef="{{i}}-{{column.columnDef}}">
<ng-container *matFooterCellDef>
<td mat-footer-cell *ngIf="onDisplayFooter(footer, datasource.data)"
[attr.colspan]="TableService.getColspan(footer, datasource.data)"
class="{{TableService.getColumnClassName(column,datasource.data)}} {{TableService.getColumnClassName(column.footer,datasource.data)}}">
<div title="{{footer.title(datasource.data)}}"
class="viewData {{TableService.getColumnClassName(column,datasource.data)}}"
fxLayout="row"
[fxLayoutAlign]="footer.align ? footer.align : AlignEnum.LEFT">
{{ footer.cell(datasource.data) }}
</div>
</td>
</ng-container>
</ng-container>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: isSticky||isStickyHeader"></tr>
<tr mat-row *matRowDef="let result; columns: displayedColumns;" class="{{result.className}}"
[ngClass]="{'childRow0': !!result.isChildRow && result.parentRowClassIndex === 0,
'parentRow0': !result.isChildRow && result.parentRowClassIndex === 0,
'childRow1': !!result.isChildRow && result.parentRowClassIndex === 1,
'parentRow1': !result.isChildRow && result.parentRowClassIndex === 1}"
></tr>
<ng-container *ngFor="let df of displayedFooters">
<tr mat-footer-row *matFooterRowDef="df; sticky: isSticky||isStickyFooter"></tr>
</ng-container>
</table>
</div>
`,
}]
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: undefined, decorators: [{
type: Inject,
args: [InjectTokenNextSolutionsConfig]
}] }, { type: i0.Injector }, { type: i1$2.NgControl, decorators: [{
type: Self
}, {
type: Optional
}] }], propDecorators: { moduleName: [{
type: Input
}], columns: [{
type: Input
}], buttons: [{
type: Input
}], value: [{
type: Input
}], minRow: [{
type: Input
}], maxRow: [{
type: Input
}], errorMessages: [{
type: Input
}], isFormControl: [{
type: Input
}], isSticky: [{
type: Input
}], isStickyHeader: [{
type: Input
}], isStickyFooter: [{
type: Input
}], clickAction: [{
type: Output
}], onChange: [{
type: Output
}], matTable: [{
type: ViewChild,
args: ['matTable']
}], isExpandRowTable: [{
type: Input
}], expandRowProperty: [{
type: Input
}] } });
/**
* Đây chỉ là control trung gian khi chọn ngày, còn xử lý vẫn xử lý 2 control fromDate và toDate (mặc định)
* hoặc được truyền control name chỉ định trong input.
* Khi khai báo cần khai báo 2 control name con tương ứng nếu không mặc định 2 control con là fromDate và toDate
*/
class CvaRangeDatePickerComponent {
dateServiceUtil;
injector;
label = 'common.apply.time';
placeholderFromDate = '';
placeholderToDate = '';
/**
* giá trị là true khi muốn disabled tất cả control
*/
disabledAll = false;
/**
* giá trị là true khi muốn disabled control name fromDate
*/
disabledFromDate = false;
value = new RangeDatePickerModel();
requiredFromDate = false;
requiredToDate = false;
minDate = new Date(1900, 1, 1);
maxDate = new Date(9999, 12, 31);
onChange = new EventEmitter();
onOpenPicker = new EventEmitter();
/** key: requiredFromDate, requiredToDate, min, max */
errorMessages = new Map();
isLabelOutside = false;
isFloatLabel = true;
/** percent label outside css */
percentOfLabelOutside = 25;
fromDateControlName = 'fromDate';
toDateControlName = 'toDate';
title = '';
// config: NiceComponentLibraryConfig;
// Chỉ bằng false khi trong NsSmartTable thôi @@
isFormControl = true;
formControl;
defaultFromDate; // lưu giá trị khởi tạo ban đầu khi truyền từ bên ngoài vào
get NsValiator() {
return ValidatorService;
}
constructor(dateServiceUtil, ngControl, injector) {
this.dateServiceUtil = dateServiceUtil;
this.injector = injector;
// this.config = injector.get(InjectTokenNextSolutionsConfig);
if (ngControl) {
// Hành động này thay cho provide: NG_VALUE_ACCESSOR và gắn ControlValueAccessor này vào parent FormControl
ngControl.valueAccessor = this;
}
}
get fromDateValue() {
if (this.value.fromDate instanceof Date) {
return this.value.fromDate;
}
if (this.isString(this.value.fromDate) && this.value.fromDate.indexOf('Z') >= 0) {
return this.value.fromDate.replace(' ', 'T');
}
return null;
}
set fromDateValue(val) {
this.value.fromDate = val;
}
get toDateValue() {
if (this.value.toDate instanceof Date) {
return this.value.toDate;
}
if (this.isString(this.value.toDate) && this.value.toDate.indexOf('Z') >= 0) {
return this.value.toDate.replace(' ', 'T').replace('Z', '');
}
return null;
}
set toDateValue(val) {
this.value.toDate = val;
this.writeValue(this.value);
}
ngOnInit() {
this.callValidator();
}
propagateChange = (_) => {
/*NON-EMPTY FOR COMPILE*/
};
registerOnChange(fn) {
this.propagateChange(fn);
}
registerOnTouched(fn) {
this.propagateChange(fn);
}
writeValue(obj) {
if (!obj) {
obj = new RangeDatePickerModel();
}
if (!this.defaultFromDate && this.value.fromDate instanceof Date) {
this.defaultFromDate = this.prepareWriteValueData(this.value.fromDate);
}
// this.value = obj;
this.value.fromDate = this.prepareWriteValueData(obj.fromDate);
this.value.toDate = this.prepareWriteValueData(obj.toDate);
this.createTitle();
this.propagateChange(this.value);
this.callValidator();
this.onChange.emit(this.value);
if (this.defaultFromDate && this.getDisabled(this.disabledFromDate)) {
this.value.fromDate = new Date(this.defaultFromDate.replace('Z', ''));
}
}
getDisabled(disabled) {
return typeof disabled === 'function' ? disabled() : disabled;
}
createTitle() {
const titleFromDate = this.dateServiceUtil.convertDateToDisplayGMT0(this.value.fromDate);
const titleToDate = this.dateServiceUtil.convertDateToDisplayGMT0(this.value.toDate);
this.title = (titleFromDate ? titleFromDate : '') + ' - '
+ (titleToDate ? titleToDate : '');
}
callValidator() {
const ngControl = this.injector.get(NgControl);
// Nếu parent FormControl khởi tạo xong và formControl chưa có giá trị lưu
if (ngControl && !this.formControl) {
// Nếu là NsSmartTable thì phải tự new FormControl còn không thì cứ hóng parent FormControl về ^^
if (this.isFormControl) {
this.formControl = ngControl.control ? ngControl.control : undefined;
if (this.formControl && !this.formControl.value) {
this.formControl.setValue(this.value);
}
}
else {
this.formControl = new FormControl();
}
// Hành động này gắn validator vào this.formControl
// - Nếu this.formControl là parent FormControl thì sẽ show error lên FormGroup
// - Nếu this.formControl là new FormControl thì sẽ quét QueryList để check {errors}
if (this.formControl) {
// this.formControl.setValidators(NsValidator.generateNsDateRangePickerValidators(
// {
// requiredFromDate: this.requiredFromDate,
// requiredToDate: this.requiredToDate,
// }
// ));
}
}
if (this.formControl) {
// Nếu this.formControl thuộc NsSmartTable thì setValue lại
if (!this.isFormControl) {
this.formControl.setValue(this.value);
}
// Nếu là parent FormControl rồi thì kệ
if (this.formControl?.parent && this.formControl instanceof FormControl
&& this.formControl?.parent instanceof FormGroup) {
const fromDateControl = this.formControl.parent.controls[this.fromDateControlName];
if (fromDateControl) {
fromDateControl.setValue(this.value.fromDate);
}
const toDateControl = this.formControl.parent.controls[this.toDateControlName];
if (toDateControl) {
toDateControl.setValue(this.value.toDate);
}
}
this.formControl.updateValueAndValidity();
const errorsObj = {};
const errors = this.formControl.errors;
if (errors) {
Object.keys(errors).forEach(key => {
errorsObj[key] = errors[key];
});
}
if (this.checkRequired(this.requiredFromDate)) {
if (!this.value.fromDate) {
errorsObj['requiredFromDate'] = true;
}
}
if (this.checkRequired(this.requiredToDate)) {
if (!this.value.toDate) {
errorsObj['requiredToDate'] = true;
}
}
if (!(this.getDisabled(this.disabledFromDate) || this.getDisabled(this.disabledAll))) {
const minValidation = ValidatorService.customMinDateValidatorControl(this.value.fromDate, this.getMinDate());
if (minValidation) {
Object.keys(minValidation).forEach(key => {
errorsObj[key] = minValidation[key];
});
this.formControl.markAsDirty();
}
}
const maxValidation = ValidatorService.customMaxDateValidatorControl(this.value.toDate, this.getMaxDate());
if (maxValidation) {
Object.keys(maxValidation).forEach(key => {
errorsObj[key] = maxValidation[key];
});
this.formControl.markAsDirty();
}
if (Object.keys(errorsObj).length > 0) {
this.formControl.setErrors(errorsObj);
}
else {
this.formControl.setErrors(null);
}
this.formControl.markAllAsTouched();
}
}
prepareWriteValueData(val) {
let out = '';
if (val) {
if (this.isString(val) && val.toString().indexOf('Z') >= 0) {
out = this.dateServiceUtil.convertDateToStringGMT0(val);
}
else {
out = this.dateServiceUtil.convertDateToStringCurrentGMT(val);
}
}
return out;
}
isString(inputValue) {
return typeof inputValue === 'string' || inputValue instanceof String;
}
getMinDate() {
if (this.minDate) {
return this.minDate instanceof Date ? this.minDate : this.minDate();
}
return new Date(1900, 1, 1);
}
getMaxDate() {
if (this.getDisabled(this.disabledAll)) {
return new Date(9999, 12, 31);
}
if (this.maxDate) {
return this.maxDate instanceof Date ? this.maxDate : this.maxDate();
}
return new Date(9999, 12, 31);
}
checkRequired(isRequired) {
return isRequired ? typeof (isRequired) === 'boolean' ? isRequired : isRequired() : false;
}
clearRange(event) {
event.stopPropagation();
if (this.getDisabled(this.disabledFromDate)) {
this.value.toDate = '';
}
else {
this.value = new RangeDatePickerModel();
}
this.writeValue(this.value);
}
openPicker(picker) {
if (this.onOpenPicker) {
this.onOpenPicker.emit(picker);
}
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: CvaRangeDatePickerComponent, deps: [{ token: DateUtilService }, { token: i1$2.NgControl, optional: true, self: true }, { token: i0.Injector }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.5", type: CvaRangeDatePickerComponent, isStandalone: false, selector: "cva-range-date-picker", inputs: { label: "label", placeholderFromDate: "placeholderFromDate", placeholderToDate: "placeholderToDate", disabledAll: "disabledAll", disabledFromDate: "disabledFromDate", value: "value", requiredFromDate: "requiredFromDate", requiredToDate: "requiredToDate", minDate: "minDate", maxDate: "maxDate", errorMessages: "errorMessages", isLabelOutside: "isLabelOutside", isFloatLabel: "isFloatLabel", percentOfLabelOutside: "percentOfLabelOutside", fromDateControlName: "fromDateControlName", toDateControlName: "toDateControlName", isFormControl: "isFormControl" }, outputs: { onChange: "onChange", onOpenPicker: "onOpenPicker" }, providers: [
{ provide: DateAdapter, useClass: NsDateAdapter },
{
provide: MAT_DATE_FORMATS,
useValue: APP_DATE_FORMATS,
},
], ngImport: i0, template: `
<div class="cva-range-date-picker"
[ngClass]="{'labelOutside': isLabelOutside, 'float_label': isFloatLabel && !isLabelOutside}"
fxLayout="row" fxLayout.lt-sm="row wrap">
<mat-label *ngIf="isLabelOutside" class="label_width"
fxLayout="column" fxFlex="auto" fxFlex.lt-md="100%">
<div class="label">
<div>
{{ (label ? label : '') | translate }}<span
class="required-label-outside">{{ !!(requiredFromDate || requiredToDate) ? '*' : '' }}</span>
</div>
</div>
</mat-label>
<mat-form-field appearance="outline" [floatLabel]="isFloatLabel ? 'always' : 'auto'"
[hideRequiredMarker]="!isFloatLabel"
fxLayout="column" fxFlex="auto" fxFlex.lt-md="100%">
<mat-label *ngIf="!isLabelOutside && isFloatLabel">{{ (label ? label : '') | translate }}</mat-label>
<mat-date-range-input [min]="getMinDate()"
[max]="getMaxDate()"
[rangePicker]="picker"
[disabled]="getDisabled(disabledAll)"
[title]="title">
<input matStartDate
[(ngModel)]="fromDateValue"
readonly="readonly"
[placeholder]="placeholderFromDate|translate">
<input matEndDate
[(ngModel)]="toDateValue"
readOnly="true"
[placeholder]="placeholderToDate|translate">
</mat-date-range-input>
<mat-datepicker-toggle matPrefix [for]="picker"
[disabled]="getDisabled(disabledAll)">
</mat-datepicker-toggle>
<button mat-icon-button matSuffix
color="warn" class="btnDatePicker"
(click)="clearRange($event)"
[disabled]="getDisabled(disabledAll) || (checkRequired(requiredFromDate) && checkRequired(requiredToDate))"
>
<mat-icon>clear</mat-icon>
</button>
<mat-date-range-picker #picker (opened)="openPicker(picker)"></mat-date-range-picker>
<mat-hint style="color: red" *ngIf="NsValiator.invalid(formControl)">
{{ NsValiator.getErrorMessage(formControl, errorMessages) | translate }}
</mat-hint>
</mat-form-field>
</div>
`, isInline: true, dependencies: [{ kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i3.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "component", type: i5$2.MatDatepickerToggle, selector: "mat-datepicker-toggle", inputs: ["for", "tabIndex", "aria-label", "disabled", "disableRipple"], exportAs: ["matDatepickerToggle"] }, { kind: "component", type: i5$2.MatDateRangeInput, selector: "mat-date-range-input", inputs: ["rangePicker", "required", "dateFilter", "min", "max", "disabled", "separator", "comparisonStart", "comparisonEnd"], exportAs: ["matDateRangeInput"] }, { kind: "directive", type: i5$2.MatStartDate, selector: "input[matStartDate]", outputs: ["dateChange", "dateInput"] }, { kind: "directive", type: i5$2.MatEndDate, selector: "input[matEndDate]", outputs: ["dateChange", "dateInput"] }, { kind: "component", type: i5$2.MatDateRangePicker, selector: "mat-date-range-picker", exportAs: ["matDateRangePicker"] }, { kind: "component", type: i6.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i6.MatLabel, selector: "mat-label" }, { kind: "directive", type: i6.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "directive", type: i6.MatPrefix, selector: "[matPrefix], [matIconPrefix], [matTextPrefix]", inputs: ["matTextPrefix"] }, { kind: "directive", type: i6.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "component", type: i7.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { kind: "directive", type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { kind: "directive", type: i9.DefaultClassDirective, selector: " [ngClass], [ngClass.xs], [ngClass.sm], [ngClass.md], [ngClass.lg], [ngClass.xl], [ngClass.lt-sm], [ngClass.lt-md], [ngClass.lt-lg], [ngClass.lt-xl], [ngClass.gt-xs], [ngClass.gt-sm], [ngClass.gt-md], [ngClass.gt-lg]", inputs: ["ngClass", "ngClass.xs", "ngClass.sm", "ngClass.md", "ngClass.lg", "ngClass.xl", "ngClass.lt-sm", "ngClass.lt-md", "ngClass.lt-lg", "ngClass.lt-xl", "ngClass.gt-xs", "ngClass.gt-sm", "ngClass.gt-md", "ngClass.gt-lg"] }, { kind: "pipe", type: i1.TranslatePipe, name: "translate" }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: CvaRangeDatePickerComponent, decorators: [{
type: Component,
args: [{
selector: 'cva-range-date-picker',
standalone: false,
template: `
<div class="cva-range-date-picker"
[ngClass]="{'labelOutside': isLabelOutside, 'float_label': isFloatLabel && !isLabelOutside}"
fxLayout="row" fxLayout.lt-sm="row wrap">
<mat-label *ngIf="isLabelOutside" class="label_width"
fxLayout="column" fxFlex="auto" fxFlex.lt-md="100%">
<div class="label">
<div>
{{ (label ? label : '') | translate }}<span
class="required-label-outside">{{ !!(requiredFromDate || requiredToDate) ? '*' : '' }}</span>
</div>
</div>
</mat-label>
<mat-form-field appearance="outline" [floatLabel]="isFloatLabel ? 'always' : 'auto'"
[hideRequiredMarker]="!isFloatLabel"
fxLayout="column" fxFlex="auto" fxFlex.lt-md="100%">
<mat-label *ngIf="!isLabelOutside && isFloatLabel">{{ (label ? label : '') | translate }}</mat-label>
<mat-date-range-input [min]="getMinDate()"
[max]="getMaxDate()"
[rangePicker]="picker"
[disabled]="getDisabled(disabledAll)"
[title]="title">
<input matStartDate
[(ngModel)]="fromDateValue"
readonly="readonly"
[placeholder]="placeholderFromDate|translate">
<input matEndDate
[(ngModel)]="toDateValue"
readOnly="true"
[placeholder]="placeholderToDate|translate">
</mat-date-range-input>
<mat-datepicker-toggle matPrefix [for]="picker"
[disabled]="getDisabled(disabledAll)">
</mat-datepicker-toggle>
<button mat-icon-button matSuffix
color="warn" class="btnDatePicker"
(click)="clearRange($event)"
[disabled]="getDisabled(disabledAll) || (checkRequired(requiredFromDate) && checkRequired(requiredToDate))"
>
<mat-icon>clear</mat-icon>
</button>
<mat-date-range-picker #picker (opened)="openPicker(picker)"></mat-date-range-picker>
<mat-hint style="color: red" *ngIf="NsValiator.invalid(formControl)">
{{ NsValiator.getErrorMessage(formControl, errorMessages) | translate }}
</mat-hint>
</mat-form-field>
</div>
`,
providers: [
{ provide: DateAdapter, useClass: NsDateAdapter },
{
provide: MAT_DATE_FORMATS,
useValue: APP_DATE_FORMATS,
},
],
}]
}], ctorParameters: () => [{ type: DateUtilService }, { type: i1$2.NgControl, decorators: [{
type: Self
}, {
type: Optional
}] }, { type: i0.Injector }], propDecorators: { label: [{
type: Input
}], placeholderFromDate: [{
type: Input
}], placeholderToDate: [{
type: Input
}], disabledAll: [{
type: Input
}], disabledFromDate: [{
type: Input
}], value: [{
type: Input
}], requiredFromDate: [{
type: Input
}], requiredToDate: [{
type: Input
}], minDate: [{
type: Input
}], maxDate: [{
type: Input
}], onChange: [{
type: Output
}], onOpenPicker: [{
type: Output
}], errorMessages: [{
type: Input
}], isLabelOutside: [{
type: Input
}], isFloatLabel: [{
type: Input
}], percentOfLabelOutside: [{
type: Input
}], fromDateControlName: [{
type: Input
}], toDateControlName: [{
type: Input
}], isFormControl: [{
type: Input
}] } });
class DragDropDirective {
onFileDropped = new EventEmitter();
background = '#f5fcff';
opacity = '1';
//Dragover listener
onDragOver(evt) {
evt.preventDefault();
evt.stopPropagation();
this.background = '#9ecbec';
this.opacity = '0.8';
}
//Dragleave listener
onDragLeave(evt) {
evt.preventDefault();
evt.stopPropagation();
this.background = '#f5fcff';
this.opacity = '1';
}
//Drop listener
ondrop(evt) {
evt.preventDefault();
evt.stopPropagation();
this.background = '#f5fcff';
this.opacity = '1';
let files = evt?.dataTransfer?.files;
if (files && files.length > 0) {
this.onFileDropped.emit(files);
}
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: DragDropDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.1.5", type: DragDropDirective, isStandalone: false, selector: "[appDragDrop]", outputs: { onFileDropped: "onFileDropped" }, host: { listeners: { "dragover": "onDragOver($event)", "dragleave": "onDragLeave($event)", "drop": "ondrop($event)" }, properties: { "style.background-color": "this.background", "style.opacity": "this.opacity" } }, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: DragDropDirective, decorators: [{
type: Directive,
args: [{
selector: '[appDragDrop]',
standalone: false,
}]
}], propDecorators: { onFileDropped: [{
type: Output
}], background: [{
type: HostBinding,
args: ['style.background-color']
}], opacity: [{
type: HostBinding,
args: ['style.opacity']
}], onDragOver: [{
type: HostListener,
args: ['dragover', ['$event']]
}], onDragLeave: [{
type: HostListener,
args: ['dragleave', ['$event']]
}], ondrop: [{
type: HostListener,
args: ['drop', ['$event']]
}] } });
class CvaMultiUploadComponent {
fileUpload;
files = [];
multiple = false;
maxSize = null;
accept = null;
label = '';
required = '';
disabled = false;
/* percent label outside css */
percentOfLabelOutside = 25;
onFileChange = new EventEmitter();
sizeError = null;
typeError = null;
propagateChange = (_) => {
/*NON-EMPTY FOR COMPILE*/
};
writeValue(obj) {
if (!obj) {
return;
}
if (this.multiple) {
this.files.push(obj);
}
else {
this.files = [obj];
}
this.propagateChange(this.files);
}
registerOnChange(fn) {
this.propagateChange = fn;
}
registerOnTouched() {
/*NON-EMPTY FOR COMPILE*/
}
onClick() {
const fileUpload = this.fileUpload?.nativeElement;
fileUpload.click();
}
convertToUploadModel(fileList) {
this.sizeError = null;
this.typeError = null;
if (fileList && fileList[0]) {
if (!this.validFile(fileList)) {
return;
}
for (let i = 0; i < fileList.length; i++) {
const file = fileList[i];
if (this.isContainFileName(file.name)) {
continue;
}
const reader = new FileReader();
reader.onload = (event) => {
this.writeValue(new UploadModel(file.name, file, event.target.result));
if (!this.multiple || i === fileList.length - 1) {
this.onFileChange.emit();
}
};
reader.readAsDataURL(file);
if (!this.multiple) {
break;
}
}
}
}
isContainFileName(name) {
for (const file of this.files) {
if (file.name === name) {
return true;
}
}
return false;
}
onFileChangeAction(event) {
const target = event.target;
if (target && target.files) {
this.convertToUploadModel(target.files);
}
}
onFileDroppedAction(fileList) {
this.convertToUploadModel(fileList);
}
validFile(fileList) {
const acceptStr = this.accept ? this.accept.join() : '';
for (let i = 0; i < fileList.length; i++) {
const file = fileList[i];
if (acceptStr.indexOf(file.type) < 0 || !file.type || file.type === '') {
this.typeError = file.name;
return false;
}
if (this.maxSize && file.size > this.maxSize) {
this.sizeError = file.name;
return false;
}
}
return true;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: CvaMultiUploadComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.5", type: CvaMultiUploadComponent, isStandalone: false, selector: "cva-multi-upload", inputs: { files: "files", multiple: "multiple", maxSize: "maxSize", accept: "accept", label: "label", required: "required", disabled: "disabled", percentOfLabelOutside: "percentOfLabelOutside" }, outputs: { onFileChange: "onFileChange" }, providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => CvaMultiUploadComponent),
multi: true,
},
], viewQueries: [{ propertyName: "fileUpload", first: true, predicate: ["fileUpload"], descendants: true }], ngImport: i0, template: `
<div class="cva-multi-upload"
fxLayout="row" fxLayout.lt-sm="row wrap">
<mat-label *ngIf="label" class="label_width"
fxLayout="column" fxFlex="auto" fxFlex.lt-md="100%">
<div class="label">{{ (label ? label : '') | translate }}<span
class="required-label-outside">{{ !!required ? '*' : '' }}</span></div>
</mat-label>
<div class="uploadArea"
fxLayout="column" fxFlex="auto" fxFlex.lt-md="100%"
appDragDrop (onFileDropped)="onFileDroppedAction($event)">
<input type="file" multiple #fileUpload (change)="onFileChangeAction($event)"
[disabled]="disabled"
accept="{{accept ? accept.join() : '*/*'}}">
<mat-card>
<mat-card-actions>
<button mat-button class="upload-button" color="warn" (click)="onClick()">
<mat-icon>add</mat-icon>
<span>{{ 'common.upload.file' | translate }}</span>
</button>
</mat-card-actions>
<mat-card-content>
</mat-card-content>
</mat-card>
<mat-error *ngIf="sizeError!==null">{{ sizeError + ' ' + ('common.is.over-size' | translate) }}</mat-error>
<mat-error *ngIf="typeError!==null">{{ typeError + ' ' + ('common.is.not-accept' | translate) }}</mat-error>
</div>
</div>
`, isInline: true, dependencies: [{ kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i3.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "component", type: i3$3.MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "directive", type: i3$3.MatCardActions, selector: "mat-card-actions", inputs: ["align"], exportAs: ["matCardActions"] }, { kind: "directive", type: i3$3.MatCardContent, selector: "mat-card-content" }, { kind: "directive", type: i6.MatLabel, selector: "mat-label" }, { kind: "directive", type: i6.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "component", type: i7.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { kind: "directive", type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { kind: "directive", type: DragDropDirective, selector: "[appDragDrop]", outputs: ["onFileDropped"] }, { kind: "pipe", type: i1.TranslatePipe, name: "translate" }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: CvaMultiUploadComponent, decorators: [{
type: Component,
args: [{
selector: 'cva-multi-upload',
standalone: false,
template: `
<div class="cva-multi-upload"
fxLayout="row" fxLayout.lt-sm="row wrap">
<mat-label *ngIf="label" class="label_width"
fxLayout="column" fxFlex="auto" fxFlex.lt-md="100%">
<div class="label">{{ (label ? label : '') | translate }}<span
class="required-label-outside">{{ !!required ? '*' : '' }}</span></div>
</mat-label>
<div class="uploadArea"
fxLayout="column" fxFlex="auto" fxFlex.lt-md="100%"
appDragDrop (onFileDropped)="onFileDroppedAction($event)">
<input type="file" multiple #fileUpload (change)="onFileChangeAction($event)"
[disabled]="disabled"
accept="{{accept ? accept.join() : '*/*'}}">
<mat-card>
<mat-card-actions>
<button mat-button class="upload-button" color="warn" (click)="onClick()">
<mat-icon>add</mat-icon>
<span>{{ 'common.upload.file' | translate }}</span>
</button>
</mat-card-actions>
<mat-card-content>
</mat-card-content>
</mat-card>
<mat-error *ngIf="sizeError!==null">{{ sizeError + ' ' + ('common.is.over-size' | translate) }}</mat-error>
<mat-error *ngIf="typeError!==null">{{ typeError + ' ' + ('common.is.not-accept' | translate) }}</mat-error>
</div>
</div>
`,
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => CvaMultiUploadComponent),
multi: true,
},
],
}]
}], propDecorators: { fileUpload: [{
type: ViewChild,
args: ['fileUpload', { static: false }]
}], files: [{
type: Input
}], multiple: [{
type: Input
}], maxSize: [{
type: Input
}], accept: [{
type: Input
}], label: [{
type: Input
}], required: [{
type: Input
}], disabled: [{
type: Input
}], percentOfLabelOutside: [{
type: Input
}], onFileChange: [{
type: Output
}] } });
class DeleteFileEventModel {
ngControl;
file;
}
class CvaUploadFileComponent {
http;
injector;
fileSaverService;
ngControl;
constructor(http, injector, fileSaverService, ngControl) {
this.http = http;
this.injector = injector;
this.fileSaverService = fileSaverService;
this.ngControl = ngControl;
if (ngControl) {
ngControl.valueAccessor = this;
}
}
fileUpload;
files = [];
maxSize = null;
height = null;
width = null;
isSquareImg = false;
isRectangleImg = false;
accept = null;
label = '';
placeholder = '';
required = false;
disabled = false;
/* percent label outside css */
percentOfLabelOutside = 25;
onFileChange = new EventEmitter();
onFileDelete = new EventEmitter();
sizeError = null;
widthError = false;
heightError = false;
isSquareError = false;
isRectangleError = false;
typeError = null;
fileType = '';
fileName = '';
imgRef = null;
default$;
set value(value) {
this.writeValue(value);
}
formControl;
set defaultUrl(fileInfo) {
this.default$ = fileInfo.url;
this.fileType = fileInfo.type;
this.fileName = fileInfo.name;
if (1 === 1) {
return;
}
const oReq = new XMLHttpRequest();
oReq.open('GET', fileInfo.url, true);
oReq.responseType = 'arraybuffer';
oReq.onload = (event) => {
const arrayBuffer = oReq.response; // Note: not oReq.responseText
if (arrayBuffer) {
// Create a blob from the response
const blob = new Blob([arrayBuffer]);
// onload needed since Google Chrome doesn't support addEventListener for FileReader
const fileReader = new FileReader();
const file = new File([blob], fileInfo.name, { type: fileInfo.type });
fileReader.onload = (event) => {
this.writeValue(new UploadModel(fileInfo.name, file, event.target.result));
};
// Load blob as Data URL
fileReader.readAsDataURL(file);
}
};
oReq.send(null);
}
ngOnInit() {
this.callValidator();
}
callValidator() {
const ngControl = this.injector.get(NgControl);
if (ngControl && !this.formControl) {
if (ngControl) {
this.formControl = ngControl.control;
}
else {
this.formControl = new FormControl();
}
}
if (this.formControl) {
if (this.required && !this.files.length) {
this.formControl.setErrors({ required: true });
}
this.formControl.markAllAsTouched();
}
}
isImageType() {
return this.fileType.startsWith('image');
}
getSrcImg() {
return this.isImageType() ? ((this.files[0]) ? this.files[0].previewValue : this.default$) : '';
}
propagateChange = (_) => {
/*NON-EMPTY FOR COMPILE*/
};
writeValue(obj) {
if (!obj) {
return;
}
if (typeof obj === 'string') {
const obj1 = { name: this.fileName, binary: null, previewValue: obj };
this.files = [obj1];
}
else if (typeof obj === 'object') {
if (obj.binary === null || obj.binary === undefined) {
const obj1 = { id: obj.id, name: obj.name, binary: null, previewValue: obj.previewValue };
this.files = [obj1];
this.fileName = obj.name;
this.fileType = obj.type ? obj.type : '';
}
else {
this.fileName = obj.name;
this.files = [obj];
}
}
this.propagateChange(this.files);
this.callValidator();
}
registerOnChange(fn) {
this.propagateChange = fn;
}
registerOnTouched() {
/*NON-EMPTY FOR COMPILE*/
}
onClick() {
const fileUpload = this.fileUpload?.nativeElement;
fileUpload.click();
}
convertToUploadModel(fileList) {
this.sizeError = null;
this.typeError = null;
if (fileList && fileList[0]) {
if (!this.validFile(fileList)) {
return;
}
for (let i = 0; i < fileList.length; i++) {
const file = fileList[i];
if (this.isContainFileName(file.name)) {
continue;
}
const reader = new FileReader();
reader.onload = (event) => {
this.writeValue(new UploadModel(file.name, file, event.target.result));
this.fileType = file.type;
this.onFileChange.emit();
};
reader.readAsDataURL(file);
break;
}
}
}
isContainFileName(name) {
for (const file of this.files) {
if (file.name === name) {
return true;
}
}
return false;
}
onFileChangeAction(event) {
const target = event.target;
if (target && target.files) {
this.convertToUploadModel(target.files);
}
}
onFileDroppedAction(fileList) {
this.convertToUploadModel(fileList);
}
validFile(fileList) {
const acceptStr = this.accept ? this.accept.join() : '';
for (let i = 0; i < fileList.length; i++) {
const file = fileList[i];
if (acceptStr.indexOf(file.type) < 0 || !file.type || file.type === '') {
this.typeError = file.name;
return false;
}
if (this.maxSize && file.size > this.maxSize) {
this.sizeError = file.name;
return false;
}
}
return true;
}
removeFiles(event, control) {
if (event) {
event.stopPropagation();
}
this.fileName = '';
this.fileType = '';
let deleteFile;
if (this.files && this.files.length > 0) {
deleteFile = this.files[0];
this.files.splice(0, 1);
this.propagateChange(this.files);
}
if (this.fileUpload) {
this.fileUpload.nativeElement.value = '';
}
this.onFileDelete.emit({ ngControl: this.ngControl, file: deleteFile });
}
onLoad(img, event) {
if (this.isSquareImg && img.height && img.width &&
(((img.height / img.width) > 1.1) || ((img.height / img.width) < 1 / 1.1))) {
this.removeFiles(undefined);
this.isSquareError = true;
return;
}
else {
this.isSquareError = false;
}
if (this.isRectangleImg && img.height && img.width &&
(((img.width / img.height) > 2.2) || ((img.width / img.height) < 2))) {
this.removeFiles(undefined);
this.isRectangleError = true;
return;
}
else {
this.isRectangleError = false;
}
if (this.width && img.width !== this.width) {
this.removeFiles(undefined);
this.widthError = true;
return;
}
else {
this.widthError = false;
}
if (this.height && img.height !== this.height) {
this.removeFiles(undefined);
this.heightError = true;
return;
}
else {
this.heightError = false;
}
const parentElement = img.closest('.preview-image');
parentElement.setAttribute('style', 'background-image:url("' + img.src + '")');
}
previewFiles(event, downloadId) {
event.stopPropagation();
downloadId.click();
}
downloadFile() {
const file = this.files[0];
if (!file) {
return;
}
if (file.id) {
// copy apiService.saveFile()
this.http.post(file.previewValue + '', null, {
headers: undefined,
params: undefined,
observe: 'response',
responseType: 'blob',
}).subscribe((l) => {
let filename = '';
const disposition = l.headers.get('Content-Disposition');
if (disposition && disposition.indexOf('attachment') !== -1) {
const filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
const matches = filenameRegex.exec(disposition);
if (matches != null && matches[1]) {
filename = matches[1].replace(/['"]/g, '');
}
}
const blobData = l.body;
const contentType = l.headers.get('Content-Type');
if (blobData && contentType) {
this.fileSaverService.save(blobData, filename, contentType);
}
});
}
else {
if (file.binary) {
this.fileSaverService.save(file.binary, file.name);
}
}
}
getRequiredErr() {
return !this.files.length && this.required && !this.heightError && !this.widthError && !this.isSquareError
&& !this.isRectangleError && !this.typeError && !this.sizeError;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: CvaUploadFileComponent, deps: [{ token: i1$3.HttpClient }, { token: i0.Injector }, { token: i2$1.FileSaverService }, { token: i1$2.NgControl, optional: true, self: true }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.5", type: CvaUploadFileComponent, isStandalone: false, selector: "cva-upload-file", inputs: { files: "files", maxSize: "maxSize", height: "height", width: "width", isSquareImg: "isSquareImg", isRectangleImg: "isRectangleImg", accept: "accept", label: "label", placeholder: "placeholder", required: "required", disabled: "disabled", percentOfLabelOutside: "percentOfLabelOutside", value: "value", defaultUrl: "defaultUrl" }, outputs: { onFileChange: "onFileChange", onFileDelete: "onFileDelete" }, viewQueries: [{ propertyName: "fileUpload", first: true, predicate: ["fileUpload"], descendants: true }], ngImport: i0, template: `
<div class="cva-multi-upload labelOutside"
fxLayout="row" fxLayout.lt-sm="row wrap">
<mat-label *ngIf="label" class="label_width"
fxLayout="column" fxFlex="auto" fxFlex.lt-md="100%">
<div class="label">{{ (label ? label : '') | translate }}<span
class="required-label-outside">{{ !!required ? '*' : '' }}</span></div>
</mat-label>
<div class="uploadArea" style="background-color: #FFFFFF"
fxLayout="column" fxFlex="auto" fxFlex.lt-md="100%"
appDragDrop (onFileDropped)="onFileDroppedAction($event)">
<input type="file" #fileUpload (change)="onFileChangeAction($event)"
[disabled]="disabled"
accept="{{accept ? accept.join() : '*/*'}}">
<mat-card>
<mat-card-actions>
<div fxLayout="column">
<button mat-button
class="{{(isImageType() && files[0])?'upload-button preview': 'upload-button'}}"
color="warn" (click)="onClick()">
<div class="preview-image"
*ngIf="isImageType() && files[0]">
<img (load)="onLoad(img, $event)"
#img
style="display: none"
[src]="getSrcImg()| secure | async"
*ngIf="isImageType() && files[0]"
/>
</div>
<i [ngClass]="files[0]?'fa fa-file-alt':'fa fa-plus'"
*ngIf="!isImageType() || !files[0]"></i>
<span
*ngIf="!files[0]">{{ ((placeholder ? placeholder : 'common.button.import.file')| translate) }}</span>
<i *ngIf="!!files[0]?.previewValue && !isImageType()" class="fa fa-eye"
(click)="previewFiles($event, downloadId)">
<a download (click)="downloadFile()" #downloadId style="display:none;"></a>
</i>
<i *ngIf="files[0] && !disabled" class="fa fa-trash-alt"
(click)="removeFiles($event, this)"></i>
</button>
</div>
<mat-label>{{ fileName }}</mat-label>
</mat-card-actions>
<mat-card-content>
</mat-card-content>
</mat-card>
<mat-error
*ngIf="sizeError!==null">{{ sizeError + ' ' + ('common.is.over-size' | translate) }}
</mat-error>
<mat-error
*ngIf="typeError!==null">{{ typeError + ' ' + ('common.is.not-accept' | translate) }}
</mat-error>
<mat-error *ngIf="getRequiredErr()">{{ ('common.error.required' | translate) }}</mat-error>
<mat-error *ngIf="widthError">{{ ('common.error.image.width' | translate) }}</mat-error>
<mat-error *ngIf="heightError">{{ ('common.error.image.height' | translate) }}</mat-error>
<mat-error *ngIf="isSquareError">{{ ('common.error.image.square' | translate) }}</mat-error>
<mat-error *ngIf="isRectangleError">{{ ('common.error.image.rectangle' | translate) }}</mat-error>
</div>
</div>
`, isInline: true, dependencies: [{ kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i3.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "component", type: i3$3.MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "directive", type: i3$3.MatCardActions, selector: "mat-card-actions", inputs: ["align"], exportAs: ["matCardActions"] }, { kind: "directive", type: i3$3.MatCardContent, selector: "mat-card-content" }, { kind: "directive", type: i6.MatLabel, selector: "mat-label" }, { kind: "directive", type: i6.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "directive", type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { kind: "directive", type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { kind: "directive", type: i9.DefaultClassDirective, selector: " [ngClass], [ngClass.xs], [ngClass.sm], [ngClass.md], [ngClass.lg], [ngClass.xl], [ngClass.lt-sm], [ngClass.lt-md], [ngClass.lt-lg], [ngClass.lt-xl], [ngClass.gt-xs], [ngClass.gt-sm], [ngClass.gt-md], [ngClass.gt-lg]", inputs: ["ngClass", "ngClass.xs", "ngClass.sm", "ngClass.md", "ngClass.lg", "ngClass.xl", "ngClass.lt-sm", "ngClass.lt-md", "ngClass.lt-lg", "ngClass.lt-xl", "ngClass.gt-xs", "ngClass.gt-sm", "ngClass.gt-md", "ngClass.gt-lg"] }, { kind: "directive", type: DragDropDirective, selector: "[appDragDrop]", outputs: ["onFileDropped"] }, { kind: "pipe", type: i2.AsyncPipe, name: "async" }, { kind: "pipe", type: i1.TranslatePipe, name: "translate" }, { kind: "pipe", type: SecureImgPipe, name: "secure" }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: CvaUploadFileComponent, decorators: [{
type: Component,
args: [{
selector: 'cva-upload-file',
standalone: false,
template: `
<div class="cva-multi-upload labelOutside"
fxLayout="row" fxLayout.lt-sm="row wrap">
<mat-label *ngIf="label" class="label_width"
fxLayout="column" fxFlex="auto" fxFlex.lt-md="100%">
<div class="label">{{ (label ? label : '') | translate }}<span
class="required-label-outside">{{ !!required ? '*' : '' }}</span></div>
</mat-label>
<div class="uploadArea" style="background-color: #FFFFFF"
fxLayout="column" fxFlex="auto" fxFlex.lt-md="100%"
appDragDrop (onFileDropped)="onFileDroppedAction($event)">
<input type="file" #fileUpload (change)="onFileChangeAction($event)"
[disabled]="disabled"
accept="{{accept ? accept.join() : '*/*'}}">
<mat-card>
<mat-card-actions>
<div fxLayout="column">
<button mat-button
class="{{(isImageType() && files[0])?'upload-button preview': 'upload-button'}}"
color="warn" (click)="onClick()">
<div class="preview-image"
*ngIf="isImageType() && files[0]">
<img (load)="onLoad(img, $event)"
#img
style="display: none"
[src]="getSrcImg()| secure | async"
*ngIf="isImageType() && files[0]"
/>
</div>
<i [ngClass]="files[0]?'fa fa-file-alt':'fa fa-plus'"
*ngIf="!isImageType() || !files[0]"></i>
<span
*ngIf="!files[0]">{{ ((placeholder ? placeholder : 'common.button.import.file')| translate) }}</span>
<i *ngIf="!!files[0]?.previewValue && !isImageType()" class="fa fa-eye"
(click)="previewFiles($event, downloadId)">
<a download (click)="downloadFile()" #downloadId style="display:none;"></a>
</i>
<i *ngIf="files[0] && !disabled" class="fa fa-trash-alt"
(click)="removeFiles($event, this)"></i>
</button>
</div>
<mat-label>{{ fileName }}</mat-label>
</mat-card-actions>
<mat-card-content>
</mat-card-content>
</mat-card>
<mat-error
*ngIf="sizeError!==null">{{ sizeError + ' ' + ('common.is.over-size' | translate) }}
</mat-error>
<mat-error
*ngIf="typeError!==null">{{ typeError + ' ' + ('common.is.not-accept' | translate) }}
</mat-error>
<mat-error *ngIf="getRequiredErr()">{{ ('common.error.required' | translate) }}</mat-error>
<mat-error *ngIf="widthError">{{ ('common.error.image.width' | translate) }}</mat-error>
<mat-error *ngIf="heightError">{{ ('common.error.image.height' | translate) }}</mat-error>
<mat-error *ngIf="isSquareError">{{ ('common.error.image.square' | translate) }}</mat-error>
<mat-error *ngIf="isRectangleError">{{ ('common.error.image.rectangle' | translate) }}</mat-error>
</div>
</div>
`,
}]
}], ctorParameters: () => [{ type: i1$3.HttpClient }, { type: i0.Injector }, { type: i2$1.FileSaverService }, { type: i1$2.NgControl, decorators: [{
type: Self
}, {
type: Optional
}] }], propDecorators: { fileUpload: [{
type: ViewChild,
args: ['fileUpload', { static: false }]
}], files: [{
type: Input
}], maxSize: [{
type: Input
}], height: [{
type: Input
}], width: [{
type: Input
}], isSquareImg: [{
type: Input
}], isRectangleImg: [{
type: Input
}], accept: [{
type: Input
}], label: [{
type: Input
}], placeholder: [{
type: Input
}], required: [{
type: Input
}], disabled: [{
type: Input
}], percentOfLabelOutside: [{
type: Input
}], onFileChange: [{
type: Output
}], onFileDelete: [{
type: Output
}], value: [{
type: Input
}], defaultUrl: [{
type: Input
}] } });
class CvaMultiUploadImgComponent {
injector;
ngControl;
files = [];
formArray = new FormArray([]);
isFix = false;
maxControls = -1;
disabled = false;
constructor(injector, ngControl) {
this.injector = injector;
this.ngControl = ngControl;
if (ngControl) {
// Hành động này thay cho provide: NG_VALUE_ACCESSOR và gắn ControlValueAccessor này vào parent FormControl
ngControl.valueAccessor = this;
}
}
propagateChange = (_) => {
/*NON-EMPTY FOR COMPILE*/
};
get FileTypes() {
return FileTypeEnum;
}
getControls() {
return this.formArray.controls;
}
writeValue(value) {
this.formArray.clear();
const remain = this.isFix ? (this.maxControls === -1 ? value.length : this.maxControls)
: (this.maxControls === -1 ? (value.length + 1) : this.maxControls);
for (let i = 0; i < remain; i++) {
const url = i < value.length ? value[i] : '';
this.formArray.push(new FormGroup({
imageUrl: new FormControl(url),
}));
}
this.formArray.valueChanges.subscribe(res => {
this.propagateChange(res);
});
}
registerOnChange(fn) {
this.propagateChange = fn;
}
registerOnTouched() {
/*NON-EMPTY FOR COMPILE*/
}
onFileDelete(event) {
if (this.isFix) {
return;
}
this.formArray.removeAt(event.index);
if ((this.formArray.length + 1) === this.maxControls) {
this.formArray.push(new FormGroup({
imageUrl: new FormControl(''),
}));
}
}
onFileChange(event) {
if ((event.index < this.formArray.length - 1) || this.isFix || (event.index === this.maxControls - 1)) {
return;
}
this.formArray.push(new FormGroup({
imageUrl: new FormControl(''),
}));
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: CvaMultiUploadImgComponent, deps: [{ token: i0.Injector }, { token: i1$2.NgControl, optional: true, self: true }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.5", type: CvaMultiUploadImgComponent, isStandalone: false, selector: "cva-multi-upload-img", inputs: { isFix: "isFix", maxControls: "maxControls", disabled: "disabled" }, ngImport: i0, template: `
<div style="align-items: flex-start" fxLayout="row wrap">
<ng-container *ngFor="let control of getControls(); let i = index" [formGroup]="control">
<cva-upload-file style="margin-right: 20px"
formControlName="imageUrl" (onFileDelete)="onFileDelete({control:control, index:i})"
(onFileChange)="onFileChange({control:control, index:i})"
[defaultUrl]="{url: '', name: ' ', type: 'image/png'}"
[accept]="[FileTypes.PNG, FileTypes.JPG]"
[disabled]="disabled"
></cva-upload-file>
</ng-container>
</div>
`, isInline: true, dependencies: [{ kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { kind: "component", type: CvaUploadFileComponent, selector: "cva-upload-file", inputs: ["files", "maxSize", "height", "width", "isSquareImg", "isRectangleImg", "accept", "label", "placeholder", "required", "disabled", "percentOfLabelOutside", "value", "defaultUrl"], outputs: ["onFileChange", "onFileDelete"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: CvaMultiUploadImgComponent, decorators: [{
type: Component,
args: [{
selector: 'cva-multi-upload-img',
standalone: false,
template: `
<div style="align-items: flex-start" fxLayout="row wrap">
<ng-container *ngFor="let control of getControls(); let i = index" [formGroup]="control">
<cva-upload-file style="margin-right: 20px"
formControlName="imageUrl" (onFileDelete)="onFileDelete({control:control, index:i})"
(onFileChange)="onFileChange({control:control, index:i})"
[defaultUrl]="{url: '', name: ' ', type: 'image/png'}"
[accept]="[FileTypes.PNG, FileTypes.JPG]"
[disabled]="disabled"
></cva-upload-file>
</ng-container>
</div>
`,
}]
}], ctorParameters: () => [{ type: i0.Injector }, { type: i1$2.NgControl, decorators: [{
type: Self
}, {
type: Optional
}] }], propDecorators: { isFix: [{
type: Input
}], maxControls: [{
type: Input
}], disabled: [{
type: Input
}] } });
class CvaBreadcrumbComponent {
activatedRoute;
breadcrumbList = [];
updateLabel = new EventEmitter();
constructor(activatedRoute) {
this.activatedRoute = activatedRoute;
}
ngOnInit() {
this.breadcrumbList = this.buildBreadCrumb(this.activatedRoute.root);
}
buildBreadCrumb(route, url = '', breadcrumbs = []) {
let label = route.routeConfig
? (route.routeConfig.data ? route.routeConfig.data['breadcrumb'] : 'common.missing.router.data.breadcrumb')
: '';
if (this.updateLabel.observers.length > 0) {
const out = { label };
this.updateLabel.emit(out);
label = out.label;
}
let path = route.routeConfig && route.routeConfig.path ? route.routeConfig.path : '';
if (route.snapshot && route.snapshot.params) {
Object.keys(route.snapshot.params).forEach(key => {
label = label.replace(':' + key, route.snapshot.params[key]);
path = path.replace(':' + key, route.snapshot.params[key]);
});
}
const nextUrl = `${url}${path}/`;
if (nextUrl.endsWith('//')) {
return breadcrumbs;
}
const breadcrumb = new BreadCrumbModel(label, nextUrl);
const newBreadcrumbs = [...breadcrumbs, breadcrumb];
if (route.firstChild) {
return this.buildBreadCrumb(route.firstChild, nextUrl, newBreadcrumbs);
}
return newBreadcrumbs;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: CvaBreadcrumbComponent, deps: [{ token: i1$4.ActivatedRoute }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.5", type: CvaBreadcrumbComponent, isStandalone: false, selector: "cva-breadcrumb", outputs: { updateLabel: "updateLabel" }, ngImport: i0, template: `
<ul class="cva-breadcrumb">
<div class="breadcrumbList">
<li *ngFor="let item of breadcrumbList; let i = index">
<a [routerLink]="'/' + item.url" *ngIf="i!==breadcrumbList.length-1">
{{ item.label | translate }}
</a>
<span class="separator" *ngIf="i!==breadcrumbList.length-1"> <i class="fa fa-angle-right"></i> </span>
<span class="currentAction" *ngIf="i===breadcrumbList.length-1">{{ item.label | translate }}</span>
</li>
</div>
</ul>
`, isInline: true, dependencies: [{ kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$4.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "pipe", type: i1.TranslatePipe, name: "translate" }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: CvaBreadcrumbComponent, decorators: [{
type: Component,
args: [{
selector: 'cva-breadcrumb',
standalone: false,
template: `
<ul class="cva-breadcrumb">
<div class="breadcrumbList">
<li *ngFor="let item of breadcrumbList; let i = index">
<a [routerLink]="'/' + item.url" *ngIf="i!==breadcrumbList.length-1">
{{ item.label | translate }}
</a>
<span class="separator" *ngIf="i!==breadcrumbList.length-1"> <i class="fa fa-angle-right"></i> </span>
<span class="currentAction" *ngIf="i===breadcrumbList.length-1">{{ item.label | translate }}</span>
</li>
</div>
</ul>
`,
}]
}], ctorParameters: () => [{ type: i1$4.ActivatedRoute }], propDecorators: { updateLabel: [{
type: Output
}] } });
class CvaLoaderComponent {
loaderService;
imgSrc = '';
constructor(loaderService) {
this.loaderService = loaderService;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: CvaLoaderComponent, deps: [{ token: LoaderService }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.5", type: CvaLoaderComponent, isStandalone: false, selector: "cva-loader", inputs: { imgSrc: "imgSrc" }, ngImport: i0, template: `
<div class="cva-loader progress-loader" *ngIf="loaderService.isLoading | async">
<div class="loading-spinner">
<mat-progress-bar color="warn" mode="indeterminate">
</mat-progress-bar>
<mat-progress-spinner color="warn" mode="indeterminate" diameter="200" strokeWidth="15">
</mat-progress-spinner>
</div>
<img *ngIf="!!imgSrc" [src]="imgSrc" alt=""/>
</div>
`, isInline: true, dependencies: [{ kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i3$4.MatProgressBar, selector: "mat-progress-bar", inputs: ["color", "value", "bufferValue", "mode"], outputs: ["animationEnd"], exportAs: ["matProgressBar"] }, { kind: "component", type: i9$2.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "pipe", type: i2.AsyncPipe, name: "async" }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: CvaLoaderComponent, decorators: [{
type: Component,
args: [{
selector: 'cva-loader',
standalone: false,
template: `
<div class="cva-loader progress-loader" *ngIf="loaderService.isLoading | async">
<div class="loading-spinner">
<mat-progress-bar color="warn" mode="indeterminate">
</mat-progress-bar>
<mat-progress-spinner color="warn" mode="indeterminate" diameter="200" strokeWidth="15">
</mat-progress-spinner>
</div>
<img *ngIf="!!imgSrc" [src]="imgSrc" alt=""/>
</div>
`,
}]
}], ctorParameters: () => [{ type: LoaderService }], propDecorators: { imgSrc: [{
type: Input
}] } });
class CvaTreeComponent {
_treeFields = new FlatTreeModel();
autocompleteData = [];
set treeData(treeFields) {
if (treeFields && treeFields.rootData && treeFields.rootData.length > 0) {
this._treeFields = treeFields;
this.autocompleteData = UtilsService.convertTreeDataToAutocompleteData(this._treeFields, this.symbol, this.hasChild, this._treeFields.rootData, null);
this.onSelectChange();
}
}
placeholder = '';
symbol = ' >> ';
isShowLeafNextTo = false;
disabled = false;
isHidingTree = false;
selectionChange = new EventEmitter();
treeControl = new NestedTreeControl(node => {
return this._treeFields && this._treeFields.children ? this._treeFields.children(node) : [];
});
dataSource = new MatTreeNestedDataSource();
autocompleteControl = new FormControl();
constructor() {
}
propagateChange = (_) => {
/*NON-EMPTY FOR COMPILE*/
};
writeValue(obj) {
if (this._treeFields) {
this.dataSource.data = this._treeFields.rootData;
this.treeControl.dataNodes = this._treeFields.rootData;
if (obj) {
this.updateTreeChecked(this._treeFields.rootData, obj);
this.autocompleteControl.setValue(obj);
this.propagateChange(obj);
this.selectionChange.emit(obj);
}
}
}
registerOnChange(fn) {
this.propagateChange = fn;
}
registerOnTouched() {
/*NON-EMPTY FOR COMPILE*/
}
hasChild = (_, node) => {
if (this._treeFields && this._treeFields.children) {
const children = this._treeFields.children(node);
return children && children.length > 0;
}
return false;
};
onSelectChange() {
const selectedValues = this.autocompleteControl.value;
this.writeValue(selectedValues);
this.treeControl.collapseAll();
}
updateTreeChecked(nodes, selectedValues) {
if (this._treeFields) {
for (const node of nodes) {
if (this.hasChild(0, node)) {
this.updateTreeChecked(this._treeFields.children(node), selectedValues);
}
else {
node.checked = !selectedValues || selectedValues.length === 0; // Nếu selectedValues.length === 0 thì showAll
if (selectedValues && selectedValues.length > 0) {
const value = this._treeFields.value(node).toString().toLowerCase();
if (selectedValues instanceof Array) {
selectedValues.forEach((selectedValue) => {
node.checked = node.checked || value === selectedValue.toLowerCase();
if (node.checked) {
return;
}
});
}
else {
node.checked = value === selectedValues.toLowerCase();
}
}
}
}
}
}
isShowNodeRecursive(nodes) {
let result = false;
if (this._treeFields) {
for (const node of nodes) {
result = result || node.checked
|| (this.hasChild(0, node) && this.isShowNodeRecursive(this._treeFields.children(node)));
if (result) {
break;
}
}
}
return result;
}
isMatchFilterInputValue(node) {
const selectedValues = this.autocompleteControl.value;
if (selectedValues && selectedValues.length > 0) {
return node.checked ? node.checked : false;
}
return false;
}
isShowButtonChoose(node) {
if (this.disabled) {
return false;
}
const selectedValues = this.autocompleteControl.value;
if (!selectedValues || selectedValues.length <= 0) {
return false;
}
return !node.checked;
}
isShowButtonRemove(node) {
if (this.disabled) {
return false;
}
const selectedValues = this.autocompleteControl.value;
if (!selectedValues || selectedValues.length <= 0) {
return false;
}
return node.checked ? node.checked : false;
}
onChooseNode(node) {
const selectedValues = this.autocompleteControl.value;
if (selectedValues && selectedValues.length > 0 && this._treeFields) {
let isExists = false;
for (const selectedValue of selectedValues) {
isExists = isExists || selectedValue.toLowerCase() === this._treeFields.value(node).toString().toLowerCase();
}
if (!isExists) {
selectedValues.push(this._treeFields.value(node).toString());
this.writeValue(selectedValues);
}
}
}
onRemoveNode(node) {
const selectedValues = this.autocompleteControl.value;
if (selectedValues && selectedValues.length > 0 && this._treeFields) {
const index = selectedValues.indexOf(this._treeFields.value(node).toString());
if (index >= 0) {
selectedValues.splice(index, 1);
this.writeValue(selectedValues);
}
}
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: CvaTreeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.5", type: CvaTreeComponent, isStandalone: false, selector: "cva-tree", inputs: { treeData: "treeData", placeholder: "placeholder", symbol: "symbol", isShowLeafNextTo: "isShowLeafNextTo", disabled: "disabled", isHidingTree: "isHidingTree" }, outputs: { selectionChange: "selectionChange" }, providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => CvaTreeComponent),
multi: true,
},
], ngImport: i0, template: `
<div class="cva-tree">
<div class="box-search">
<cva-multi-select-autocomplete [multiple]="!isHidingTree" [placeholder]="placeholder|translate"
[options]="autocompleteData" style="width: 100%"
[formControl]="autocompleteControl" [disabled]="disabled"
(selectionChange)="onSelectChange()"
[isTree]="true" [treeSymbol]="symbol">
</cva-multi-select-autocomplete>
<div class="expand_collapse" *ngIf="!isHidingTree">
<button mat-icon-button color="warn" (click)="treeControl.collapseAll()"
matTooltip="{{'common.tree.collapseAll'|translate}}">
<mat-icon>unfold_less</mat-icon>
</button>
<button mat-icon-button color="warn" (click)="treeControl.expandAll()"
matTooltip="{{'common.tree.expandAll'|translate}}">
<mat-icon>unfold_more</mat-icon>
</button>
</div>
</div>
<div class="parent-mat-tree" *ngIf="!isHidingTree">
<mat-tree [dataSource]="dataSource" [treeControl]="treeControl" class="example-tree">
<!-- This is the tree node template for leaf nodes -->
<mat-tree-node *matTreeNodeDef="let node" matTreeNodeToggle
[ngClass]="{'example-tree-invisible': !isShowLeafNextTo && !isShowNodeRecursive([node]),
'mat-tree-node': isShowNodeRecursive([node])}">
<li fxLayoutAlign="space-between center" fxLayout>
<div class="mat-tree-node">
<!-- use a disabled button to provide padding for tree leaf -->
<button mat-icon-button disabled></button>
<label [ngClass]="{'item-focused': isMatchFilterInputValue(node)}">
{{_treeFields.display(node)}}</label>
</div>
<div class="mat-tree-node-button">
<button mat-icon-button color="warn" (click)="onChooseNode(node)"
*ngIf="isShowButtonChoose(node)"
matTooltip="{{'common.tree.add'|translate}}">
<mat-icon>add</mat-icon>
</button>
<button mat-icon-button color="warn" (click)="onRemoveNode(node)"
*ngIf="isShowButtonRemove(node)"
matTooltip="{{'common.tree.remove'|translate}}">
<mat-icon>clear</mat-icon>
</button>
</div>
</li>
</mat-tree-node>
<!-- This is the tree node template for expandable nodes -->
<mat-nested-tree-node *matTreeNodeDef="let node; when: hasChild"
[ngClass]="{'example-tree-invisible': !isShowNodeRecursive([node])}">
<li>
<div class="mat-tree-node">
<button mat-icon-button matTreeNodeToggle
[attr.aria-label]="'toggle ' + _treeFields.value(node)">
<mat-icon class="mat-icon-rtl-mirror">
{{treeControl.isExpanded(node) ? 'expand_more' : 'chevron_right'}}
</mat-icon>
</button>
<label [ngClass]="{'item-focused': isMatchFilterInputValue(node)}">
{{_treeFields.display(node)}}</label>
</div>
<ul *ngIf="!treeControl.isExpanded(node)">
<ng-container matTreeNodeOutlet></ng-container>
</ul>
</li>
</mat-nested-tree-node>
</mat-tree>
</div>
</div>
`, isInline: true, dependencies: [{ kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: i3.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "component", type: i7.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: i8$1.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "directive", type: i6$1.MatNestedTreeNode, selector: "mat-nested-tree-node", inputs: ["matNestedTreeNode", "disabled", "tabIndex"], outputs: ["activation", "expandedChange"], exportAs: ["matNestedTreeNode"] }, { kind: "directive", type: i6$1.MatTreeNodeDef, selector: "[matTreeNodeDef]", inputs: ["matTreeNodeDefWhen", "matTreeNode"] }, { kind: "directive", type: i6$1.MatTreeNodeToggle, selector: "[matTreeNodeToggle]", inputs: ["matTreeNodeToggleRecursive"] }, { kind: "component", type: i6$1.MatTree, selector: "mat-tree", exportAs: ["matTree"] }, { kind: "directive", type: i6$1.MatTreeNode, selector: "mat-tree-node", inputs: ["tabIndex", "disabled"], outputs: ["activation", "expandedChange"], exportAs: ["matTreeNode"] }, { kind: "directive", type: i6$1.MatTreeNodeOutlet, selector: "[matTreeNodeOutlet]" }, { kind: "directive", type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { kind: "directive", type: i8.DefaultLayoutAlignDirective, selector: " [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]", inputs: ["fxLayoutAlign", "fxLayoutAlign.xs", "fxLayoutAlign.sm", "fxLayoutAlign.md", "fxLayoutAlign.lg", "fxLayoutAlign.xl", "fxLayoutAlign.lt-sm", "fxLayoutAlign.lt-md", "fxLayoutAlign.lt-lg", "fxLayoutAlign.lt-xl", "fxLayoutAlign.gt-xs", "fxLayoutAlign.gt-sm", "fxLayoutAlign.gt-md", "fxLayoutAlign.gt-lg"] }, { kind: "directive", type: i9.DefaultClassDirective, selector: " [ngClass], [ngClass.xs], [ngClass.sm], [ngClass.md], [ngClass.lg], [ngClass.xl], [ngClass.lt-sm], [ngClass.lt-md], [ngClass.lt-lg], [ngClass.lt-xl], [ngClass.gt-xs], [ngClass.gt-sm], [ngClass.gt-md], [ngClass.gt-lg]", inputs: ["ngClass", "ngClass.xs", "ngClass.sm", "ngClass.md", "ngClass.lg", "ngClass.xl", "ngClass.lt-sm", "ngClass.lt-md", "ngClass.lt-lg", "ngClass.lt-xl", "ngClass.gt-xs", "ngClass.gt-sm", "ngClass.gt-md", "ngClass.gt-lg"] }, { kind: "component", type: CvaMultiSelectAutocomplete, selector: "cva-multi-select-autocomplete", inputs: ["placeholder", "label", "hint", "value", "options", "disabled", "errorMessages", "multiple", "required", "isTree", "treeSymbol", "sizeOfItemsInListByPixels", "isLabelOutside", "isFloatLabel", "percentOfLabelOutside", "isFormControl"], outputs: ["selectionChange", "selectedOptionDataChange"] }, { kind: "pipe", type: i1.TranslatePipe, name: "translate" }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: CvaTreeComponent, decorators: [{
type: Component,
args: [{
selector: 'cva-tree',
standalone: false,
template: `
<div class="cva-tree">
<div class="box-search">
<cva-multi-select-autocomplete [multiple]="!isHidingTree" [placeholder]="placeholder|translate"
[options]="autocompleteData" style="width: 100%"
[formControl]="autocompleteControl" [disabled]="disabled"
(selectionChange)="onSelectChange()"
[isTree]="true" [treeSymbol]="symbol">
</cva-multi-select-autocomplete>
<div class="expand_collapse" *ngIf="!isHidingTree">
<button mat-icon-button color="warn" (click)="treeControl.collapseAll()"
matTooltip="{{'common.tree.collapseAll'|translate}}">
<mat-icon>unfold_less</mat-icon>
</button>
<button mat-icon-button color="warn" (click)="treeControl.expandAll()"
matTooltip="{{'common.tree.expandAll'|translate}}">
<mat-icon>unfold_more</mat-icon>
</button>
</div>
</div>
<div class="parent-mat-tree" *ngIf="!isHidingTree">
<mat-tree [dataSource]="dataSource" [treeControl]="treeControl" class="example-tree">
<!-- This is the tree node template for leaf nodes -->
<mat-tree-node *matTreeNodeDef="let node" matTreeNodeToggle
[ngClass]="{'example-tree-invisible': !isShowLeafNextTo && !isShowNodeRecursive([node]),
'mat-tree-node': isShowNodeRecursive([node])}">
<li fxLayoutAlign="space-between center" fxLayout>
<div class="mat-tree-node">
<!-- use a disabled button to provide padding for tree leaf -->
<button mat-icon-button disabled></button>
<label [ngClass]="{'item-focused': isMatchFilterInputValue(node)}">
{{_treeFields.display(node)}}</label>
</div>
<div class="mat-tree-node-button">
<button mat-icon-button color="warn" (click)="onChooseNode(node)"
*ngIf="isShowButtonChoose(node)"
matTooltip="{{'common.tree.add'|translate}}">
<mat-icon>add</mat-icon>
</button>
<button mat-icon-button color="warn" (click)="onRemoveNode(node)"
*ngIf="isShowButtonRemove(node)"
matTooltip="{{'common.tree.remove'|translate}}">
<mat-icon>clear</mat-icon>
</button>
</div>
</li>
</mat-tree-node>
<!-- This is the tree node template for expandable nodes -->
<mat-nested-tree-node *matTreeNodeDef="let node; when: hasChild"
[ngClass]="{'example-tree-invisible': !isShowNodeRecursive([node])}">
<li>
<div class="mat-tree-node">
<button mat-icon-button matTreeNodeToggle
[attr.aria-label]="'toggle ' + _treeFields.value(node)">
<mat-icon class="mat-icon-rtl-mirror">
{{treeControl.isExpanded(node) ? 'expand_more' : 'chevron_right'}}
</mat-icon>
</button>
<label [ngClass]="{'item-focused': isMatchFilterInputValue(node)}">
{{_treeFields.display(node)}}</label>
</div>
<ul *ngIf="!treeControl.isExpanded(node)">
<ng-container matTreeNodeOutlet></ng-container>
</ul>
</li>
</mat-nested-tree-node>
</mat-tree>
</div>
</div>
`,
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => CvaTreeComponent),
multi: true,
},
],
}]
}], ctorParameters: () => [], propDecorators: { treeData: [{
type: Input
}], placeholder: [{
type: Input
}], symbol: [{
type: Input
}], isShowLeafNextTo: [{
type: Input
}], disabled: [{
type: Input
}], isHidingTree: [{
type: Input
}], selectionChange: [{
type: Output
}] } });
class CvaRadiobuttonComponent {
injector;
placeholder = '';
value;
hint = '';
options = [];
disabled = false;
required = false;
direction = 'horizontal';
errorMessages = new Map();
onChange = new EventEmitter();
// Chỉ bằng false khi trong NsSmartTable thôi nhé @@
isFormControl = true;
control = undefined;
get selectedValue() {
return this.value;
}
set selectedValue(val) {
this.writeValue(val);
}
get NsValidator() {
return ValidatorService;
}
constructor(injector, ngControl) {
this.injector = injector;
if (ngControl) {
ngControl.valueAccessor = this;
}
}
ngOnChanges() {
this.writeValue(this.value);
}
ngOnInit() {
this.callValidator();
}
writeValue(value) {
if (value !== undefined) {
this.value = value;
this.propagateChange(this.value);
this.callValidator();
this.onChange.emit(this.value);
}
}
propagateChange = (_) => {
/*NON-EMPTY FOR COMPILE*/
};
registerOnChange(fn) {
this.propagateChange = fn;
}
registerOnTouched() {
/*NON-EMPTY FOR COMPILE*/
}
callValidator() {
const ngControl = this.injector.get(NgControl);
// Nếu parent FormControl khởi tạo xong và formControl chưa có giá trị lưu
if (ngControl && !this.control) {
// Nếu là NsSmartTable thì phải tự new FormControl còn không thì cứ hóng parent FormControl về ^^
if (this.isFormControl) {
this.control = ngControl.control ? ngControl.control : undefined;
}
else {
this.control = new FormControl();
}
// Hành động này gắn validator vào this.formControl
// - Nếu this.formControl là parent FormControl thì sẽ show error lên FormGroup
// - Nếu this.formControl là new FormControl thì sẽ quét QueryList để check {errors}
if (this.control) {
if (this.control.validator) {
if (this.required) {
this.control.setValidators([Validators.required, this.control.validator]);
}
else {
this.control.setValidators([this.control.validator]);
}
}
else {
if (this.required) {
this.control.setValidators([Validators.required]);
}
}
}
}
if (this.control) {
// Nếu this.formControl thuộc NsSmartTable thì setValue lại
if (!this.isFormControl) {
this.control.setValue(this.selectedValue);
}
// Nếu là parent FormControl rồi thì kệ
this.control.updateValueAndValidity();
}
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: CvaRadiobuttonComponent, deps: [{ token: i0.Injector }, { token: i1$2.NgControl, optional: true, self: true }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.5", type: CvaRadiobuttonComponent, isStandalone: false, selector: "cva-radiobutton", inputs: { placeholder: "placeholder", value: "value", hint: "hint", options: "options", disabled: "disabled", required: "required", direction: "direction", errorMessages: "errorMessages", isFormControl: "isFormControl" }, outputs: { onChange: "onChange" }, usesOnChanges: true, ngImport: i0, template: `
<div class="cva-radiobutton ábc {{!!placeholder ? 'labelOutside' : ''}}"
fxLayout="row" fxLayout.lt-sm="row wrap">
<mat-label id="example-radio-group-label" *ngIf="!!placeholder" class="label_width"
fxLayout="column" fxFlex="auto" fxFlex.lt-md="100%">
<div class="label">
<div>
{{placeholder | translate}}<span class="required-label-outside">{{!!required ? '*' : ''}}</span>
</div>
</div>
</mat-label>
<div fxLayout="column" fxFlex="auto" fxFlex.lt-md="100%">
<mat-radio-group
aria-labelledby="example-radio-group-label"
class="example-radio-group" [disabled]="disabled"
[(ngModel)]="selectedValue"
fxLayout="{{direction === 'horizontal' ? 'row' : 'column'}}">
<mat-radio-button class="example-radio-button"
*ngFor="let option of options"
[value]="option.value"
[disabled]="option.disabled">
{{option.displayValue | translate}}
</mat-radio-button>
</mat-radio-group>
<mat-hint align="start" *ngIf="!NsValidator.invalid(control) && !hint">{{hint | translate}}</mat-hint>
<mat-hint align="start" *ngIf="NsValidator.invalid(control)">{{NsValidator.getErrorMessage(control, errorMessages) | translate}}</mat-hint>
</div>
</div>
`, isInline: true, dependencies: [{ kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i6.MatLabel, selector: "mat-label" }, { kind: "directive", type: i6.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "directive", type: i4$3.MatRadioGroup, selector: "mat-radio-group", inputs: ["color", "name", "labelPosition", "value", "selected", "disabled", "required", "disabledInteractive"], outputs: ["change"], exportAs: ["matRadioGroup"] }, { kind: "component", type: i4$3.MatRadioButton, selector: "mat-radio-button", inputs: ["id", "name", "aria-label", "aria-labelledby", "aria-describedby", "disableRipple", "tabIndex", "checked", "value", "labelPosition", "disabled", "required", "color", "disabledInteractive"], outputs: ["change"], exportAs: ["matRadioButton"] }, { kind: "directive", type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { kind: "directive", type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { kind: "pipe", type: i1.TranslatePipe, name: "translate" }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: CvaRadiobuttonComponent, decorators: [{
type: Component,
args: [{
selector: 'cva-radiobutton',
standalone: false,
template: `
<div class="cva-radiobutton ábc {{!!placeholder ? 'labelOutside' : ''}}"
fxLayout="row" fxLayout.lt-sm="row wrap">
<mat-label id="example-radio-group-label" *ngIf="!!placeholder" class="label_width"
fxLayout="column" fxFlex="auto" fxFlex.lt-md="100%">
<div class="label">
<div>
{{placeholder | translate}}<span class="required-label-outside">{{!!required ? '*' : ''}}</span>
</div>
</div>
</mat-label>
<div fxLayout="column" fxFlex="auto" fxFlex.lt-md="100%">
<mat-radio-group
aria-labelledby="example-radio-group-label"
class="example-radio-group" [disabled]="disabled"
[(ngModel)]="selectedValue"
fxLayout="{{direction === 'horizontal' ? 'row' : 'column'}}">
<mat-radio-button class="example-radio-button"
*ngFor="let option of options"
[value]="option.value"
[disabled]="option.disabled">
{{option.displayValue | translate}}
</mat-radio-button>
</mat-radio-group>
<mat-hint align="start" *ngIf="!NsValidator.invalid(control) && !hint">{{hint | translate}}</mat-hint>
<mat-hint align="start" *ngIf="NsValidator.invalid(control)">{{NsValidator.getErrorMessage(control, errorMessages) | translate}}</mat-hint>
</div>
</div>
`,
}]
}], ctorParameters: () => [{ type: i0.Injector }, { type: i1$2.NgControl, decorators: [{
type: Self
}, {
type: Optional
}] }], propDecorators: { placeholder: [{
type: Input
}], value: [{
type: Input
}], hint: [{
type: Input
}], options: [{
type: Input
}], disabled: [{
type: Input
}], required: [{
type: Input
}], direction: [{
type: Input
}], errorMessages: [{
type: Input
}], onChange: [{
type: Output
}], isFormControl: [{
type: Input
}] } });
class FlatTreeService {
static hasChild(_nodeData) {
return !!_nodeData.children && Array.isArray(_nodeData.children) && _nodeData.children.length > 0;
}
static convertTreeToFlatTree(inputData, config) {
if (!inputData) {
return [];
}
inputData.forEach(node => {
this.setRequiredFlatNoteProperty(node, config);
if (node.children && node.children.length > 0) {
this.convertTreeToFlatTree(node.children, config);
}
});
return inputData;
}
static setRequiredFlatNoteProperty(node, config) {
node.children = (node.children && node.children.length > 0) ? node.children : null;
node._displayFuncInput = config.isDynamicConfig ? config.display : typeof (config.display) === 'function' ? config.display(node) : config.display;
node.display = typeof node._displayFuncInput === 'function' ? node._displayFuncInput(node) : node._displayFuncInput;
node._disabledFuncInput = config.isDynamicConfig ? config.disabled : typeof (config.disabled) === 'function' ? config.disabled(node) : config.disabled;
node.disabled = typeof node._disabledFuncInput === 'function' ? node._disabledFuncInput(node) : node._disabledFuncInput;
return node;
}
}
class CvaFlatTreeNodeLeftComponent {
treeControl;
isHideCheckbox = false;
node = new FlatTreeNodeModel();
toggle = new EventEmitter();
onParentNodeClick = new EventEmitter();
onLeafNodeClick = new EventEmitter();
ngModelParentChange = new EventEmitter();
ngModelLeafChange = new EventEmitter();
nodeClicked;
menubar = menubar;
hasChild = (node) => !!node.children && Array.isArray(node.children) && node.children.length > 0;
checkDisabledNode(node) {
return node.disabled || this.getDisabledInputFunc(node);
}
getDisabledInputFunc(node) {
return typeof (node._disabledFuncInput) === 'function' ? node._disabledFuncInput(node) : !!node._disabledFuncInput;
}
descendantsAllSelected(node) {
if (this.treeControl) {
const descendants = this.treeControl.getDescendants(node);
return descendants.length > 0 && descendants.every(child => {
return child.checked;
});
}
return false;
}
descendantsPartiallySelected(node) {
if (this.treeControl) {
const descendants = this.treeControl.getDescendants(node);
const result = descendants.some(child => child.checked);
return result && !this.descendantsAllSelected(node);
}
return false;
}
onDisabledParent(parent) {
if (!parent.disabled) {
return false;
}
else if (this.treeControl) {
this.treeControl.getDescendants(parent).forEach(childNode => childNode.disabled = true);
return true;
}
else {
return false;
}
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: CvaFlatTreeNodeLeftComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.5", type: CvaFlatTreeNodeLeftComponent, isStandalone: false, selector: "cva-flat-tree-node-left", inputs: { treeControl: "treeControl", isHideCheckbox: "isHideCheckbox", node: "node", nodeClicked: "nodeClicked" }, outputs: { toggle: "toggle", onParentNodeClick: "onParentNodeClick", onLeafNodeClick: "onLeafNodeClick", ngModelParentChange: "ngModelParentChange", ngModelLeafChange: "ngModelLeafChange" }, ngImport: i0, template: `
<ng-container [ngSwitch]="hasChild(node)">
<ng-container *ngSwitchCase="false">
<div
class="label-area {{isHideCheckbox ? 'isClickDiv' : ''}} {{isHideCheckbox && nodeClicked?.value === node.value ? 'nodeSelected': ''}}"
(click)="onLeafNodeClick.emit()"
fxLayoutAlign="space-between center">
<button *ngIf="node.level > 0" type="button" mat-icon-button disabled></button>
{{ node.displayValue }}
</div>
<mat-checkbox [(ngModel)]="node.checked"
[checked]="node.checked"
(ngModelChange)="ngModelLeafChange.emit($event)"
[disabled]="checkDisabledNode(node)"
*ngIf="!isHideCheckbox">
</mat-checkbox>
</ng-container>
<ng-container *ngSwitchCase="true">
<div
class="label-area {{isHideCheckbox ? 'isClickDiv' : ''}} {{isHideCheckbox && nodeClicked?.value === node.value ? 'nodeSelected': ''}}"
fxLayoutAlign="space-between center">
<button type="button" mat-icon-button (click)="toggle.emit()"
[attr.aria-label]="'toggle ' + node.displayValue">
<i class="fas {{(treeControl && treeControl.isExpanded(node)) ? 'fa-chevron-up' : 'fa-chevron-down'}}"></i>
</button>
<span (click)="onParentNodeClick.emit()">{{ node.displayValue }}</span>
</div>
<mat-checkbox [(ngModel)]="node.checked"
*ngIf="!isHideCheckbox"
[checked]="descendantsAllSelected(node)"
[disabled]="onDisabledParent(node) || getDisabledInputFunc(node)"
[indeterminate]="descendantsPartiallySelected(node)"
(ngModelChange)="ngModelParentChange.emit($event)">
</mat-checkbox>
</ng-container>
</ng-container>
`, isInline: true, dependencies: [{ kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i2.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i3.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "component", type: i4$1.MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "directive", type: i8.DefaultLayoutAlignDirective, selector: " [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]", inputs: ["fxLayoutAlign", "fxLayoutAlign.xs", "fxLayoutAlign.sm", "fxLayoutAlign.md", "fxLayoutAlign.lg", "fxLayoutAlign.xl", "fxLayoutAlign.lt-sm", "fxLayoutAlign.lt-md", "fxLayoutAlign.lt-lg", "fxLayoutAlign.lt-xl", "fxLayoutAlign.gt-xs", "fxLayoutAlign.gt-sm", "fxLayoutAlign.gt-md", "fxLayoutAlign.gt-lg"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: CvaFlatTreeNodeLeftComponent, decorators: [{
type: Component,
args: [{
selector: 'cva-flat-tree-node-left',
standalone: false,
template: `
<ng-container [ngSwitch]="hasChild(node)">
<ng-container *ngSwitchCase="false">
<div
class="label-area {{isHideCheckbox ? 'isClickDiv' : ''}} {{isHideCheckbox && nodeClicked?.value === node.value ? 'nodeSelected': ''}}"
(click)="onLeafNodeClick.emit()"
fxLayoutAlign="space-between center">
<button *ngIf="node.level > 0" type="button" mat-icon-button disabled></button>
{{ node.displayValue }}
</div>
<mat-checkbox [(ngModel)]="node.checked"
[checked]="node.checked"
(ngModelChange)="ngModelLeafChange.emit($event)"
[disabled]="checkDisabledNode(node)"
*ngIf="!isHideCheckbox">
</mat-checkbox>
</ng-container>
<ng-container *ngSwitchCase="true">
<div
class="label-area {{isHideCheckbox ? 'isClickDiv' : ''}} {{isHideCheckbox && nodeClicked?.value === node.value ? 'nodeSelected': ''}}"
fxLayoutAlign="space-between center">
<button type="button" mat-icon-button (click)="toggle.emit()"
[attr.aria-label]="'toggle ' + node.displayValue">
<i class="fas {{(treeControl && treeControl.isExpanded(node)) ? 'fa-chevron-up' : 'fa-chevron-down'}}"></i>
</button>
<span (click)="onParentNodeClick.emit()">{{ node.displayValue }}</span>
</div>
<mat-checkbox [(ngModel)]="node.checked"
*ngIf="!isHideCheckbox"
[checked]="descendantsAllSelected(node)"
[disabled]="onDisabledParent(node) || getDisabledInputFunc(node)"
[indeterminate]="descendantsPartiallySelected(node)"
(ngModelChange)="ngModelParentChange.emit($event)">
</mat-checkbox>
</ng-container>
</ng-container>
`,
}]
}], propDecorators: { treeControl: [{
type: Input
}], isHideCheckbox: [{
type: Input
}], node: [{
type: Input
}], toggle: [{
type: Output
}], onParentNodeClick: [{
type: Output
}], onLeafNodeClick: [{
type: Output
}], ngModelParentChange: [{
type: Output
}], ngModelLeafChange: [{
type: Output
}], nodeClicked: [{
type: Input
}] } });
class CvaFlatTreeNodeRightComponent {
treeControl;
node = new FlatTreeNodeModel();
isView = false;
toggle = new EventEmitter();
deSelectLeafNode = new EventEmitter();
deSelectParentNode = new EventEmitter();
hasChild = (node) => !!node.children && Array.isArray(node.children) && node.children.length > 0;
checkDisabledNode(node) {
return node.disabled || this.getDisabledInputFunc(node);
}
getDisabledInputFunc(node) {
return typeof (node._disabledFuncInput) === 'function' ? node._disabledFuncInput(node) : !!node._disabledFuncInput;
}
checkIsView(isView) {
return isView ? typeof (isView) === 'boolean' ? isView : isView() : false;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: CvaFlatTreeNodeRightComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.5", type: CvaFlatTreeNodeRightComponent, isStandalone: false, selector: "cva-flat-tree-node-right", inputs: { treeControl: "treeControl", node: "node", isView: "isView" }, outputs: { toggle: "toggle", deSelectLeafNode: "deSelectLeafNode", deSelectParentNode: "deSelectParentNode" }, ngImport: i0, template: `
<ng-container [ngSwitch]="hasChild(node)">
<ng-container *ngSwitchCase="false">
<div style="width: 100%"
fxLayout="row"
fxLayoutAlign="space-between center">
<div class="label-area"
fxLayout="row"
fxLayoutAlign="space-between center">
<button *ngIf="node.level > 0" type="button" mat-icon-button disabled></button>
{{ node.displayValue }}
</div>
<button type="button" mat-icon-button class="danger"
*ngIf="!(checkDisabledNode(node) || checkIsView(isView))"
(click)="deSelectLeafNode.emit()">
<i class="far fa-trash-alt"></i>
</button>
</div>
</ng-container>
<ng-container *ngSwitchCase="true">
<div style="width: 100%"
fxLayout="row"
fxLayoutAlign="space-between center">
<div class="label-area"
fxLayout="row"
fxLayoutAlign="space-between center">
<button type="button" mat-icon-button (click)="toggle.emit()"
[attr.aria-label]="'toggle ' + node.displayValue">
<i class="fas {{treeControl?.isExpanded(node) ? 'fa-chevron-up' : 'fa-chevron-down'}}"></i>
</button>
{{ node.displayValue }}
</div>
<button type="button" mat-icon-button class="danger"
*ngIf="!(checkDisabledNode(node) || checkIsView(isView))"
(click)="deSelectParentNode.emit()">
<i class="far fa-trash-alt"></i>
</button>
</div>
</ng-container>
</ng-container>
`, isInline: true, dependencies: [{ kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i2.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "component", type: i3.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "directive", type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { kind: "directive", type: i8.DefaultLayoutAlignDirective, selector: " [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]", inputs: ["fxLayoutAlign", "fxLayoutAlign.xs", "fxLayoutAlign.sm", "fxLayoutAlign.md", "fxLayoutAlign.lg", "fxLayoutAlign.xl", "fxLayoutAlign.lt-sm", "fxLayoutAlign.lt-md", "fxLayoutAlign.lt-lg", "fxLayoutAlign.lt-xl", "fxLayoutAlign.gt-xs", "fxLayoutAlign.gt-sm", "fxLayoutAlign.gt-md", "fxLayoutAlign.gt-lg"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: CvaFlatTreeNodeRightComponent, decorators: [{
type: Component,
args: [{
selector: 'cva-flat-tree-node-right',
standalone: false,
template: `
<ng-container [ngSwitch]="hasChild(node)">
<ng-container *ngSwitchCase="false">
<div style="width: 100%"
fxLayout="row"
fxLayoutAlign="space-between center">
<div class="label-area"
fxLayout="row"
fxLayoutAlign="space-between center">
<button *ngIf="node.level > 0" type="button" mat-icon-button disabled></button>
{{ node.displayValue }}
</div>
<button type="button" mat-icon-button class="danger"
*ngIf="!(checkDisabledNode(node) || checkIsView(isView))"
(click)="deSelectLeafNode.emit()">
<i class="far fa-trash-alt"></i>
</button>
</div>
</ng-container>
<ng-container *ngSwitchCase="true">
<div style="width: 100%"
fxLayout="row"
fxLayoutAlign="space-between center">
<div class="label-area"
fxLayout="row"
fxLayoutAlign="space-between center">
<button type="button" mat-icon-button (click)="toggle.emit()"
[attr.aria-label]="'toggle ' + node.displayValue">
<i class="fas {{treeControl?.isExpanded(node) ? 'fa-chevron-up' : 'fa-chevron-down'}}"></i>
</button>
{{ node.displayValue }}
</div>
<button type="button" mat-icon-button class="danger"
*ngIf="!(checkDisabledNode(node) || checkIsView(isView))"
(click)="deSelectParentNode.emit()">
<i class="far fa-trash-alt"></i>
</button>
</div>
</ng-container>
</ng-container>
`,
}]
}], propDecorators: { treeControl: [{
type: Input
}], node: [{
type: Input
}], isView: [{
type: Input
}], toggle: [{
type: Output
}], deSelectLeafNode: [{
type: Output
}], deSelectParentNode: [{
type: Output
}] } });
class CvaFlatTreeComponent {
translateService;
injector;
cdr;
label = '';
required = false;
value = [];
valueObjRef = new Map();
multiple = true;
disabled;
isView = false;
isDisplayChooseTreeOnly = false;
isHideCheckbox = false;
isCollapseSelected = false;
selectedLabelTitle = 'common.selected.tree.label';
/** height of tree view */
viewHeight = 300; // px
/** height of node view */
itemSize = 48; // px
paddingLeft = 20; //px
/* percent label outside css */
percentOfLabelOutside = 25;
treeConfig;
isSearchOutSide = false;
searchTextOutSide = '';
searchText = '';
errorMessages = new Map();
fullDatasource = [];
filterDatasource = [];
treeControl;
treeFlattener;
dataSource;
fullDataTreeControl;
fullDataTreeFlattener;
fullDataDataSource;
selectedTreeControl;
selectedTreeFlattener;
selectedDataSource;
selectedFullDataSource = [];
selectedFullValues = new Map();
selectionChange = new EventEmitter();
onNodeClick = new EventEmitter();
nodeClicked;
// Chỉ bằng false khi trong NsSmartTable thôi nhé @@
isFormControl = true;
// Cái này là để gắn khi nó là FormControl trong 1 FormGroup
formControl;
mapIndexes = new Map();
chooseVirtualScroll;
selectedVirtualScroll;
constructor(translateService, injector, cdr, ngControl) {
this.translateService = translateService;
this.injector = injector;
this.cdr = cdr;
if (ngControl) {
ngControl.valueAccessor = this;
}
this.fullDataTreeFlattener = new MatTreeFlattener(this.transformer, this._getLevel, this._isExpandable, this._getChildren);
this.fullDataTreeControl = new FlatTreeControl(this._getLevel, this._isExpandable);
this.fullDataDataSource = new MatTreeFlatDataSource(this.fullDataTreeControl, this.fullDataTreeFlattener);
this.fullDataDataSource.data = this.fullDatasource;
this.treeFlattener = new MatTreeFlattener(this.transformer, this._getLevel, this._isExpandable, this._getChildren);
this.treeControl = new FlatTreeControl(this._getLevel, this._isExpandable);
this.dataSource = new MatTreeFlatDataSource(this.treeControl, this.treeFlattener);
this.setDataSourceOrigin();
this.selectedTreeFlattener = new MatTreeFlattener(this.transformer, this._getLevel, this._isExpandable, this._getChildren);
this.selectedTreeControl = new FlatTreeControl(this._getLevel, this._isExpandable);
this.selectedDataSource = new MatTreeFlatDataSource(this.selectedTreeControl, this.selectedTreeFlattener);
this.setSelectedNode();
}
get NsValiator() {
return ValidatorService;
}
setSelectedNode() {
this.selectedDataSource.data = this.selectedFullDataSource;
if (this.selectedVirtualScroll) {
this.selectedVirtualScroll.checkViewportSize();
}
}
setDataSourceOrigin() {
this.fullDataDataSource.data = this.fullDatasource;
this.dataSource.data = this.filterDatasource;
if (this.chooseVirtualScroll) {
this.chooseVirtualScroll.checkViewportSize();
}
}
ngOnInit() {
this.callValidator();
}
ngAfterViewInit() {
// this.onChangeSearchText();
}
getDisplayInputFunc(node) {
return typeof (node._displayFuncInput) === 'function' ? node._displayFuncInput(node) : !!node._displayFuncInput;
}
getDisabledInputFunc(node) {
return typeof (node._disabledFuncInput) === 'function' ? node._disabledFuncInput(node) : !!node._disabledFuncInput;
}
checkDisabledNode(node) {
return node.disabled || this.getDisabledInputFunc(node);
}
callValidator() {
const ngControl = this.injector.get(NgControl);
if (ngControl && !this.formControl) {
// Nếu là NsSmartTable thì phải tự new FormControl còn không thì cứ hóng parent FormControl về ^^
if (this.isFormControl) {
this.formControl = ngControl.control ? ngControl.control : undefined;
if (this.formControl && !this.formControl.value) {
this.formControl.setValue(this.value);
}
}
else {
this.formControl = new FormControl();
}
if (this.formControl) {
// this.formControl.setValidators(NsValidator.generateNsMultiSelectValidators({
// required: this.required,
// }));
}
}
if (this.formControl) {
// Nếu this.formControl thuộc NsSmartTable thì setValue lại
if (!this.isFormControl) {
this.formControl.setValue(this.value);
}
this.formControl.updateValueAndValidity();
const errorsObj = {};
const errors = this.formControl.errors;
if (errors) {
Object.keys(errors).forEach(key => {
errorsObj[key] = errors[key];
});
}
if (this.checkRequired(this.required)) {
if (Array.isArray(this.value) && this.value.length === 0) {
errorsObj['required'] = true;
}
}
if (Object.keys(errorsObj).length > 0) {
this.formControl.setErrors(errorsObj);
}
else {
this.formControl.setErrors(null);
}
this.formControl.markAllAsTouched();
}
}
checkRequired(isRequired) {
return isRequired ? typeof (isRequired) === 'boolean' ? isRequired : isRequired() : false;
}
checkIsView(isView) {
return isView ? typeof (isView) === 'boolean' ? isView : isView() : false;
}
ngOnChanges(simpleChanges) {
if ('fullDatasource' in simpleChanges) {
// this.fullDatasource = simpleChanges.fullDatasource.currentValue;
if (!this.treeConfig) {
this.treeConfig = new FlatTreeConfigModel();
}
const currentSource = simpleChanges.fullDatasource.currentValue ? simpleChanges.fullDatasource.currentValue : [];
this.fullDatasource = FlatTreeService.convertTreeToFlatTree(currentSource, this.treeConfig);
this.filterDatasource = this.fullDatasource;
this.setDataSourceOrigin();
}
if ('treeConfig' in simpleChanges) {
this.treeConfig = simpleChanges.treeConfig.currentValue;
if (this.treeConfig) {
this.fullDatasource = FlatTreeService.convertTreeToFlatTree(this.fullDatasource, this.treeConfig);
this.filterDatasource = this.fullDatasource;
this.setDataSourceOrigin();
}
}
if ('multiple' in simpleChanges) {
this.multiple = simpleChanges.multiple.currentValue;
if (!this.multiple) {
this.isHideCheckbox = true;
}
}
if ('disabled' in simpleChanges) {
this.disabled = simpleChanges.disabled.currentValue;
if (this.disabled !== undefined && this.disabled !== null) {
if (!this.treeConfig) {
this.treeConfig = new FlatTreeConfigModel();
}
this.treeConfig.disabled = this.disabled;
this.fullDatasource = FlatTreeService.convertTreeToFlatTree(this.fullDatasource, this.treeConfig);
this.filterDatasource = this.fullDatasource;
this.setDataSourceOrigin();
}
}
if ('searchTextOutSide' in simpleChanges) {
this.searchText = simpleChanges.searchTextOutSide.currentValue ? simpleChanges.searchTextOutSide.currentValue : '';
this.onChangeSearchText();
}
if (this.value) {
this.writeValue(this.value);
}
}
transformer = (node, level) => {
node.expandable = FlatTreeService.hasChild(node);
node.level = level;
node.checked = !!node.checked;
return node;
};
propagateChange = (_) => {
/*NON-EMPTY FOR COMPILE*/
};
registerOnChange(fn) {
this.propagateChange(fn);
}
registerOnTouched(fn) {
this.propagateChange(fn);
}
writeValue(obj) {
// if (this.multiple && !obj) {
// obj = [];
// }
if (obj) {
// if (this.multiple) {
this.value = obj;
// }
this.mapIndexes = new Map();
for (let i = 0; i < this.fullDataTreeControl.dataNodes.length; i++) {
this.mapIndexes.set(this.fullDataTreeControl.dataNodes[i].value, i);
}
this.checkedDefaultValue();
this.updateSelectAll();
this.expandTreeDataSource(this.treeControl, 'isExpanded');
this.updateSelectedTree();
this.callValidator();
if (this.isView) {
this.selectedTreeControl.expandAll();
}
this.selectionChange.emit(Array.from(this.valueObjRef.values()));
}
}
updateSelectedTree() {
this.selectedFullDataSource = [];
this.getCheckedSelectedTreeDataSource(this.fullDataDataSource.data, this.selectedFullDataSource);
this.setSelectedNode();
this.expandTreeDataSource(this.selectedTreeControl, 'isExpanded');
}
checkedDefaultValue() {
this.valueObjRef.clear();
const valueSet = new Set(this.value);
for (const node of this.fullDataTreeControl.dataNodes) {
const isLeaf = !FlatTreeService.hasChild(node);
node.checked = isLeaf && valueSet.has(node.value);
if (isLeaf && node.checked) {
this.valueObjRef.set(node.value, node);
}
const orgNodeIndex = this.mapIndexes.get(node.value);
if (orgNodeIndex !== undefined) {
this.fullDataTreeControl.dataNodes[orgNodeIndex].checked = node.checked;
}
}
}
getAllChildNode(treeControl, node) {
const index = this.mapIndexes.get(node.value);
let sameLevelNextIndex = -1;
for (let i = index + 1; i < treeControl.dataNodes.length; i++) {
if (node.level >= treeControl.dataNodes[i].level) {
sameLevelNextIndex = i;
break;
}
}
return treeControl.dataNodes.slice(index + 1, sameLevelNextIndex < 0 ? treeControl.dataNodes.length : sameLevelNextIndex);
}
updateSelectAll(childrenNode) {
const data = childrenNode ? childrenNode : this.dataSource.data;
data.forEach(node => {
if (FlatTreeService.hasChild(node)) {
this.updateSelectAll(node.children);
node.checked = !!node.children && node.children.reduce((checkAll, curChildNode) => {
return checkAll && !!curChildNode.checked;
}, true);
}
});
}
checkParentNode(checked, node, isSelectedChange) {
node.checked = checked;
let indexLeaf = -1;
// update origin node
let orgNodeIndex = this.mapIndexes.get(node.value);
/*this.getNodeInFullDataSource(child)*/
this.fullDataTreeControl.dataNodes[orgNodeIndex].checked = checked;
if (orgNodeIndex > -1 && !checked) {
this.fullDataTreeControl.dataNodes[orgNodeIndex].isExpanded = false;
}
const allChild = this.getAllChildNode(this.fullDataTreeControl, node); /*this.treeControl.getDescendants(node);*/
allChild.reverse();
allChild.forEach(child => {
if (!FlatTreeService.hasChild(child)) {
indexLeaf = this.value.indexOf(child.value);
if (checked) {
if (indexLeaf < 0 && !child.disabled && child.display) {
child.checked = checked;
this.value.push(child.value);
this.valueObjRef.set(child.value, child);
}
}
else {
if ((indexLeaf >= 0 && !child.disabled && child.display) || !!isSelectedChange) {
child.checked = checked;
this.value.splice(indexLeaf, 1);
this.valueObjRef.delete(child.value);
}
}
}
else {
orgNodeIndex = this.mapIndexes.get(child.value);
if (orgNodeIndex > -1) {
this.fullDataTreeControl.dataNodes[orgNodeIndex].isExpanded = false;
this.fullDataTreeControl.dataNodes[orgNodeIndex].checked = this.fullDataTreeControl.dataNodes[orgNodeIndex].children?.every(n => n.checked);
}
}
});
if (Array.isArray(this.value) && this.value.length === 0) {
this.selectedTreeChange(node);
}
this.writeValue(this.value);
this.cdr.detectChanges();
}
selectedTreeChange(node) {
let checkExistSelected;
if (node.level < 1) {
checkExistSelected = this.selectedFullValues.has(node.value);
if (node.checked) {
this.selectedFullValues.set(node.value, node.value);
}
else if (!node.checked && checkExistSelected) {
this.selectedFullValues.delete(node.value);
}
if (node.checked) {
this.selectedTreeControl.expandDescendants(node);
}
}
else {
const rootNode = this.getRootNode(node);
if (rootNode) {
checkExistSelected = this.selectedFullValues.has(rootNode.value);
if (node.checked) {
this.selectedFullValues.set(rootNode.value, rootNode.value);
}
else if (!node.checked && checkExistSelected) {
if (!this.getAllChildNode(this.fullDataTreeControl, rootNode) /*this.treeControl.getDescendants(rootNode)*/.some(child => child.checked)) {
this.selectedFullValues.delete(node.value);
}
}
if (rootNode.checked) {
this.selectedTreeControl.expandDescendants(rootNode);
}
}
}
}
checkLeafNode(checked, node, isSelectedChange) {
if ((node.display && !this.checkDisabledNode(node)) || !!isSelectedChange) {
node.checked = checked;
// update origin node
const orgNodeIndex = this.mapIndexes.get(node.value);
this.fullDataTreeControl.dataNodes[orgNodeIndex].checked = checked;
if (checked) {
if (this.multiple) {
if (!this.value.includes(node.value)) {
this.value.push(node.value);
this.valueObjRef.set(node.value, node);
}
}
else {
this.value = [node.value];
this.valueObjRef = new Map().set(node.value, node);
}
}
else {
this.value.splice(this.value.indexOf(node.value), 1);
this.valueObjRef.delete(node.value);
}
if (Array.isArray(this.value) && this.value.length === 0) {
this.selectedTreeChange(node);
}
this.writeValue(this.value);
this.cdr.detectChanges();
}
}
/* Get the parent node of a node */
getRootNode(node) {
const currentLevel = this._getLevel(node);
if (currentLevel < 1) {
return node;
}
const startIndex = this.treeControl.dataNodes.indexOf(node) - 1;
for (let i = startIndex; i >= 0; i--) {
const currentNode = this.treeControl.dataNodes[i];
if (this._getLevel(currentNode) < currentLevel) {
return this.getRootNode(currentNode);
}
}
return node;
}
deSelect(node) {
this.checkLeafNode(false, node, true);
}
deSelectParent(node) {
this.checkParentNode(false, node, true);
}
toggleTreeControl(treeControl, node) {
treeControl.toggle(node);
const orgNode = this.fullDataTreeControl.dataNodes.find(n => n.value === node.value);
if (orgNode) {
orgNode.isFilterExpanded = treeControl.isExpanded(node);
}
this.setDataSourceOrigin();
}
toggleSelectedTree(node) {
if (node) {
this.selectedTreeControl.toggle(node);
const orgNode = this.fullDataTreeControl.dataNodes.find(n => n.value === node.value);
if (orgNode) {
orgNode.isExpanded = this.selectedTreeControl.isExpanded(node);
}
if (this.selectedVirtualScroll) {
this.selectedVirtualScroll.checkViewportSize();
}
}
else {
this.isCollapseSelected = !this.isCollapseSelected;
}
}
onChangeSearchText() {
this.filterDatasource = [];
this.getDisplayTreeDataSource(this.fullDataDataSource.data, this.filterDatasource);
this.setDataSourceOrigin();
this.expandTreeDataSource(this.treeControl, 'isFilterExpanded');
if (this.chooseVirtualScroll) {
this.chooseVirtualScroll.scrollToIndex(0);
}
}
getDisplayTreeDataSource(dataOrigin, copiedData) {
if (!Array.isArray(dataOrigin)) {
return [];
}
let copiedNode;
for (const node of dataOrigin) {
copiedNode = {
...node,
children: [],
};
if (!node.children || !FlatTreeService.hasChild(node)) {
node.display = node.displayValue.toLowerCase().includes(this.searchText.toLowerCase())
&& this.getDisplayInputFunc(node);
if (node.display) {
copiedData.push(node);
}
}
else {
this.getDisplayTreeDataSource(node.children, copiedNode.children ? copiedNode.children : []);
// parent display
node.display = (node.displayValue.toLowerCase().includes(this.searchText.toLowerCase())
|| node.children?.some(childNode => childNode.display)) && this.getDisplayInputFunc(node);
node.checked = node.children.filter(child => child.display).length > 0 &&
node.children.filter(child => child.display).every(childNode => childNode.checked);
copiedNode.display = node.display;
copiedNode.checked = node.checked;
if (node.display) {
if (!this.getAllChildNode(this.fullDataTreeControl, node).some(childNode => childNode.display)) {
this.getAllChildNode(this.fullDataTreeControl, node).forEach(childNode => childNode.display = true);
copiedData.push(node);
}
else {
copiedData.push(copiedNode);
}
}
}
}
}
getCheckedSelectedTreeDataSource(dataOrigin, copiedData) {
if (!Array.isArray(dataOrigin)) {
return [];
}
let copiedNode;
for (const node of dataOrigin) {
copiedNode = {
...node,
children: [],
};
if (!node.children || (Array.isArray(node.children) && node.children.length === 0)) {
if (node.checked) {
copiedData.push(node);
}
}
else {
this.getCheckedSelectedTreeDataSource(node.children, copiedNode.children ? copiedNode.children : []);
// parent checked
node.checked = this.getAllChildNode(this.fullDataTreeControl, node).every(childNode => childNode.checked);
node.checkedDisplay = node.checked || this.getAllChildNode(this.fullDataTreeControl, node).some(childNode => childNode.checked);
copiedNode.checkedDisplay = node.checkedDisplay;
if (node.checkedDisplay) {
if (!this.getAllChildNode(this.fullDataTreeControl, node).some(childNode => childNode.checked)) {
this.getAllChildNode(this.fullDataTreeControl, node).forEach(childNode => childNode.checked = true);
copiedData.push(node);
}
else {
copiedData.push(copiedNode);
}
}
}
}
}
expandTreeDataSource(treeControl, expandProperty) {
treeControl.dataNodes.filter(n => treeControl.isExpandable(n))
.forEach(child => {
if (child[expandProperty]) {
treeControl.expand(child);
}
else {
treeControl.collapse(child);
}
});
}
onLeafNodeClick(node) {
this.nodeClicked = node;
this.onNodeClick.emit(node);
if (this.isHideCheckbox) {
this.value = [];
this.valueObjRef.clear();
this.checkLeafNode(true, node);
}
}
onParentNodeClick(node) {
this.nodeClicked = node;
this.onNodeClick.emit(node);
if (this.isHideCheckbox) {
this.value = [];
this.valueObjRef.clear();
this.checkParentNode(true, node);
}
}
toggleNodeCheck(node, checked) {
const isLeaf = !FlatTreeService.hasChild(node);
// Gọi 1 lần duy nhất nếu là parent
const descendants = isLeaf ? [] : this.fullDataTreeControl.getDescendants(node);
const affectedNodes = isLeaf ? [node] : descendants.filter(n => !FlatTreeService.hasChild(n));
for (const leaf of affectedNodes) {
if (!leaf.display || this.checkDisabledNode(leaf))
continue;
const index = this.value.indexOf(leaf.value);
if (checked && index < 0) {
this.value.push(leaf.value);
this.valueObjRef.set(leaf.value, leaf);
leaf.checked = true;
}
if (!checked && index >= 0) {
this.value.splice(index, 1);
this.valueObjRef.delete(leaf.value);
leaf.checked = false;
}
const orgNodeIndex = this.mapIndexes.get(leaf.value);
if (orgNodeIndex !== undefined) {
this.fullDataTreeControl.dataNodes[orgNodeIndex].checked = leaf.checked;
}
}
// Nếu node là cha → cập nhật isExpanded
if (!isLeaf) {
node.checked = checked;
const orgNodeIndex = this.mapIndexes.get(node.value);
if (orgNodeIndex !== undefined) {
this.fullDataTreeControl.dataNodes[orgNodeIndex].checked = checked;
this.fullDataTreeControl.dataNodes[orgNodeIndex].isExpanded = false;
}
}
else {
node.checked = checked;
}
this.writeValue(this.value);
this.cdr.detectChanges();
}
_getLevel = (node) => node.level;
_isExpandable = (node) => FlatTreeService.hasChild(node);
_getChildren = (node) => of(node.children ? node.children : []);
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: CvaFlatTreeComponent, deps: [{ token: i1.TranslateService }, { token: i0.Injector }, { token: i0.ChangeDetectorRef }, { token: i1$2.NgControl, optional: true, self: true }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.5", type: CvaFlatTreeComponent, isStandalone: false, selector: "cva-flat-tree", inputs: { label: "label", required: "required", value: "value", multiple: "multiple", disabled: "disabled", isView: "isView", isDisplayChooseTreeOnly: "isDisplayChooseTreeOnly", isHideCheckbox: "isHideCheckbox", isCollapseSelected: "isCollapseSelected", selectedLabelTitle: "selectedLabelTitle", viewHeight: "viewHeight", itemSize: "itemSize", percentOfLabelOutside: "percentOfLabelOutside", treeConfig: "treeConfig", isSearchOutSide: "isSearchOutSide", searchTextOutSide: "searchTextOutSide", errorMessages: "errorMessages", fullDatasource: "fullDatasource", isFormControl: "isFormControl" }, outputs: { selectionChange: "selectionChange", onNodeClick: "onNodeClick" }, viewQueries: [{ propertyName: "chooseVirtualScroll", first: true, predicate: ["chooseAreaScrollViewport"], descendants: true }, { propertyName: "selectedVirtualScroll", first: true, predicate: ["selectedScrollViewport"], descendants: true }], usesOnChanges: true, ngImport: i0, template: `
<div class="cva-flat-tree labelOutside"
fxLayout="row" fxLayout.lt-sm="row wrap">
<mat-label *ngIf="label && !isSearchOutSide" class="label_width"
fxLayout="column" fxFlex="auto" fxFlex.lt-md="100%">
<div class="label">
<div>
{{ (label ? label : '') | translate }}<span class="required-label-outside">{{ required ? '*' : '' }}</span>
</div>
</div>
</mat-label>
<div class="tree-area"
fxLayout="column" fxFlex="auto" fxFlex.lt-md="100%">
<div fxLayout="row wrap">
<div class="choose-area"
*ngIf="!checkIsView(isView) && !isCollapseSelected"
fxLayout="column" fxFlex="1 1 {{isDisplayChooseTreeOnly ? '100%' : '50%'}}" fxFlex.lt-sm="100%">
<div class="header-choose-area">
<div class="title-choose-tree" fxLayout="row" fxLayout.lt-sm="row wrap">
<mat-label fxLayout="column" fxFlex="auto" fxFlex.lt-md="100%" class="label_width"
*ngIf="label && isSearchOutSide">
<div class="label">{{ (label ? label : '') | translate }}<span
class="required-label-outside">{{ required ? '*' : '' }}</span></div>
</mat-label>
<mat-divider *ngIf="label && isSearchOutSide"></mat-divider>
</div>
<mat-form-field appearance="outline"
*ngIf="!isSearchOutSide"
fxLayout="column" fxFlex="auto" fxFlex.lt-md="100%">
<input matInput
placeholder="{{'common.searchText'|translate}}"
[(ngModel)]="searchText"
(ngModelChange)="onChangeSearchText()"
autocomplete="off">
</mat-form-field>
</div>
<cdk-virtual-scroll-viewport #chooseAreaScrollViewport itemSize="{{itemSize}}"
[ngStyle]="{height: viewHeight + 'px'}">
<ng-container *cdkVirtualFor="let node of dataSource">
<cva-flat-tree-node-left
[ngStyle]="{height: itemSize + 'px', padding: '0px 0px 0px '+ (node.level * paddingLeft) +'px'}"
[attr.aria-level]="node.level"
[treeControl]="treeControl"
[isHideCheckbox]="isHideCheckbox"
[nodeClicked]="nodeClicked"
[node]="node"
(toggle)="toggleTreeControl(treeControl, node)"
(onParentNodeClick)="onParentNodeClick(node)"
(onLeafNodeClick)="onLeafNodeClick(node)"
(ngModelParentChange)="toggleNodeCheck(node, $event)"
(ngModelLeafChange)="toggleNodeCheck(node, $event)">
</cva-flat-tree-node-left>
</ng-container>
</cdk-virtual-scroll-viewport>
</div>
<div class="selected-area {{isCollapseSelected ? 'hiddenTree' : ''}}"
*ngIf="!isDisplayChooseTreeOnly"
fxLayout="column" fxFlex="1 1 {{checkIsView(isView) ? '100%' : '50%'}}" fxFlex.lt-sm="100%">
<div class="header-area" *ngIf="!isView">
<label>{{ selectedLabelTitle | translate }}{{ '(' + (value ? value.length : 0) + ')' }}</label>
<div class="collapse-expand-all" (click)="toggleSelectedTree()">
{{ (isCollapseSelected ? 'common.selected.tree.expandAll' : 'common.selected.tree.collapse') | translate }}
<i class="fa {{isCollapseSelected ? 'fa-chevron-down' : 'fa-chevron-up'}}"></i>
</div>
</div>
<cdk-virtual-scroll-viewport #selectedScrollViewport
*ngIf="!isCollapseSelected"
itemSize="{{itemSize}}" [ngStyle]="{height: viewHeight + 'px'}">
<ng-container *cdkVirtualFor="let node of selectedDataSource">
<cva-flat-tree-node-right
[ngStyle]="{height: itemSize + 'px', padding: '0px 0px 0px '+ (node.level * paddingLeft) +'px'}"
[attr.aria-level]="node.level"
[treeControl]="selectedTreeControl"
[node]="node"
[isView]="isView"
(toggle)="toggleSelectedTree(node)"
(deSelectLeafNode)="deSelect(node)"
(deSelectParentNode)="deSelectParent(node)">
</cva-flat-tree-node-right>
</ng-container>
</cdk-virtual-scroll-viewport>
</div>
</div>
<mat-hint *ngIf="NsValiator.invalid(formControl)">
{{ NsValiator.getErrorMessage(formControl, errorMessages) | translate }}
</mat-hint>
</div>
</div>
`, isInline: true, dependencies: [{ kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: i1$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i6.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i6.MatLabel, selector: "mat-label" }, { kind: "directive", type: i6.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "directive", type: i4.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "component", type: i6$2.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "directive", type: i10.CdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { kind: "directive", type: i10.CdkVirtualForOf, selector: "[cdkVirtualFor][cdkVirtualForOf]", inputs: ["cdkVirtualForOf", "cdkVirtualForTrackBy", "cdkVirtualForTemplate", "cdkVirtualForTemplateCacheSize"] }, { kind: "component", type: i10.CdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }, { kind: "directive", type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { kind: "directive", type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { kind: "directive", type: i9.DefaultStyleDirective, selector: " [ngStyle], [ngStyle.xs], [ngStyle.sm], [ngStyle.md], [ngStyle.lg], [ngStyle.xl], [ngStyle.lt-sm], [ngStyle.lt-md], [ngStyle.lt-lg], [ngStyle.lt-xl], [ngStyle.gt-xs], [ngStyle.gt-sm], [ngStyle.gt-md], [ngStyle.gt-lg]", inputs: ["ngStyle", "ngStyle.xs", "ngStyle.sm", "ngStyle.md", "ngStyle.lg", "ngStyle.xl", "ngStyle.lt-sm", "ngStyle.lt-md", "ngStyle.lt-lg", "ngStyle.lt-xl", "ngStyle.gt-xs", "ngStyle.gt-sm", "ngStyle.gt-md", "ngStyle.gt-lg"] }, { kind: "component", type: CvaFlatTreeNodeLeftComponent, selector: "cva-flat-tree-node-left", inputs: ["treeControl", "isHideCheckbox", "node", "nodeClicked"], outputs: ["toggle", "onParentNodeClick", "onLeafNodeClick", "ngModelParentChange", "ngModelLeafChange"] }, { kind: "component", type: CvaFlatTreeNodeRightComponent, selector: "cva-flat-tree-node-right", inputs: ["treeControl", "node", "isView"], outputs: ["toggle", "deSelectLeafNode", "deSelectParentNode"] }, { kind: "pipe", type: i1.TranslatePipe, name: "translate" }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: CvaFlatTreeComponent, decorators: [{
type: Component,
args: [{
selector: 'cva-flat-tree',
standalone: false,
template: `
<div class="cva-flat-tree labelOutside"
fxLayout="row" fxLayout.lt-sm="row wrap">
<mat-label *ngIf="label && !isSearchOutSide" class="label_width"
fxLayout="column" fxFlex="auto" fxFlex.lt-md="100%">
<div class="label">
<div>
{{ (label ? label : '') | translate }}<span class="required-label-outside">{{ required ? '*' : '' }}</span>
</div>
</div>
</mat-label>
<div class="tree-area"
fxLayout="column" fxFlex="auto" fxFlex.lt-md="100%">
<div fxLayout="row wrap">
<div class="choose-area"
*ngIf="!checkIsView(isView) && !isCollapseSelected"
fxLayout="column" fxFlex="1 1 {{isDisplayChooseTreeOnly ? '100%' : '50%'}}" fxFlex.lt-sm="100%">
<div class="header-choose-area">
<div class="title-choose-tree" fxLayout="row" fxLayout.lt-sm="row wrap">
<mat-label fxLayout="column" fxFlex="auto" fxFlex.lt-md="100%" class="label_width"
*ngIf="label && isSearchOutSide">
<div class="label">{{ (label ? label : '') | translate }}<span
class="required-label-outside">{{ required ? '*' : '' }}</span></div>
</mat-label>
<mat-divider *ngIf="label && isSearchOutSide"></mat-divider>
</div>
<mat-form-field appearance="outline"
*ngIf="!isSearchOutSide"
fxLayout="column" fxFlex="auto" fxFlex.lt-md="100%">
<input matInput
placeholder="{{'common.searchText'|translate}}"
[(ngModel)]="searchText"
(ngModelChange)="onChangeSearchText()"
autocomplete="off">
</mat-form-field>
</div>
<cdk-virtual-scroll-viewport #chooseAreaScrollViewport itemSize="{{itemSize}}"
[ngStyle]="{height: viewHeight + 'px'}">
<ng-container *cdkVirtualFor="let node of dataSource">
<cva-flat-tree-node-left
[ngStyle]="{height: itemSize + 'px', padding: '0px 0px 0px '+ (node.level * paddingLeft) +'px'}"
[attr.aria-level]="node.level"
[treeControl]="treeControl"
[isHideCheckbox]="isHideCheckbox"
[nodeClicked]="nodeClicked"
[node]="node"
(toggle)="toggleTreeControl(treeControl, node)"
(onParentNodeClick)="onParentNodeClick(node)"
(onLeafNodeClick)="onLeafNodeClick(node)"
(ngModelParentChange)="toggleNodeCheck(node, $event)"
(ngModelLeafChange)="toggleNodeCheck(node, $event)">
</cva-flat-tree-node-left>
</ng-container>
</cdk-virtual-scroll-viewport>
</div>
<div class="selected-area {{isCollapseSelected ? 'hiddenTree' : ''}}"
*ngIf="!isDisplayChooseTreeOnly"
fxLayout="column" fxFlex="1 1 {{checkIsView(isView) ? '100%' : '50%'}}" fxFlex.lt-sm="100%">
<div class="header-area" *ngIf="!isView">
<label>{{ selectedLabelTitle | translate }}{{ '(' + (value ? value.length : 0) + ')' }}</label>
<div class="collapse-expand-all" (click)="toggleSelectedTree()">
{{ (isCollapseSelected ? 'common.selected.tree.expandAll' : 'common.selected.tree.collapse') | translate }}
<i class="fa {{isCollapseSelected ? 'fa-chevron-down' : 'fa-chevron-up'}}"></i>
</div>
</div>
<cdk-virtual-scroll-viewport #selectedScrollViewport
*ngIf="!isCollapseSelected"
itemSize="{{itemSize}}" [ngStyle]="{height: viewHeight + 'px'}">
<ng-container *cdkVirtualFor="let node of selectedDataSource">
<cva-flat-tree-node-right
[ngStyle]="{height: itemSize + 'px', padding: '0px 0px 0px '+ (node.level * paddingLeft) +'px'}"
[attr.aria-level]="node.level"
[treeControl]="selectedTreeControl"
[node]="node"
[isView]="isView"
(toggle)="toggleSelectedTree(node)"
(deSelectLeafNode)="deSelect(node)"
(deSelectParentNode)="deSelectParent(node)">
</cva-flat-tree-node-right>
</ng-container>
</cdk-virtual-scroll-viewport>
</div>
</div>
<mat-hint *ngIf="NsValiator.invalid(formControl)">
{{ NsValiator.getErrorMessage(formControl, errorMessages) | translate }}
</mat-hint>
</div>
</div>
`,
}]
}], ctorParameters: () => [{ type: i1.TranslateService }, { type: i0.Injector }, { type: i0.ChangeDetectorRef }, { type: i1$2.NgControl, decorators: [{
type: Self
}, {
type: Optional
}] }], propDecorators: { label: [{
type: Input
}], required: [{
type: Input
}], value: [{
type: Input
}], multiple: [{
type: Input
}], disabled: [{
type: Input
}], isView: [{
type: Input
}], isDisplayChooseTreeOnly: [{
type: Input
}], isHideCheckbox: [{
type: Input
}], isCollapseSelected: [{
type: Input
}], selectedLabelTitle: [{
type: Input
}], viewHeight: [{
type: Input
}], itemSize: [{
type: Input
}], percentOfLabelOutside: [{
type: Input
}], treeConfig: [{
type: Input
}], isSearchOutSide: [{
type: Input
}], searchTextOutSide: [{
type: Input
}], errorMessages: [{
type: Input
}], fullDatasource: [{
type: Input
}], selectionChange: [{
type: Output
}], onNodeClick: [{
type: Output
}], isFormControl: [{
type: Input
}], chooseVirtualScroll: [{
type: ViewChild,
args: ['chooseAreaScrollViewport', { static: false }]
}], selectedVirtualScroll: [{
type: ViewChild,
args: ['selectedScrollViewport', { static: false }]
}] } });
class CvaDialogImportFileComponent {
matDialogRef;
apiService;
utilsService;
translateService;
data;
file;
errorImportExcelUrl = '';
inputFileRef;
constructor(matDialogRef, apiService, utilsService, translateService, data) {
this.matDialogRef = matDialogRef;
this.apiService = apiService;
this.utilsService = utilsService;
this.translateService = translateService;
this.data = data;
}
ngOnInit() {
}
onDropped(fileList) {
this.handleFile(fileList);
}
onFileChange(event, inputRef) {
const files = event.target.files;
this.handleFile(files);
}
downloadTemplate() {
if (this.data.downloadTemplateFunc)
this.data.downloadTemplateFunc();
}
onClickChooseFile(inputFile) {
inputFile.click();
}
close() {
this.matDialogRef.close();
}
onImport() {
this.utilsService.showConfirmDialog(this.data.confirmMsgKey, [])
.afterClosed().subscribe((value) => {
if (value.value) {
if (this.data.importFunc) {
this.data.importFunc(this.file).subscribe((data) => {
if (data) {
this.utilsService.onSuccessFunc(this.data.successMsgKey);
this.matDialogRef.close({ done: true, kpis: data });
}
}, errorExcelUrl => {
this.utilsService.showErrorToarst(this.data.errorMsgKey);
this.errorImportExcelUrl = errorExcelUrl;
if (this.inputFileRef) {
this.inputFileRef.nativeElement.value = '';
}
this.file = undefined;
});
}
}
});
}
downloadErrorFile() {
if (this.data.downloadErrorFile) {
this.data.downloadErrorFile(this.errorImportExcelUrl);
}
else {
this.onDownloadErrorFile();
}
}
onDownloadErrorFile() {
this.apiService.saveFile('/files/' + this.errorImportExcelUrl, null, {});
}
handleFile(files) {
if (files && files.length) {
const file = files[0];
const af = ['application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'application/vnd.ms-excel'];
if (file.type === af[0]) {
this.file = file;
}
else {
this.translateService.get("common.only.allow.excel")
.subscribe(msg => {
this.utilsService.showWarningToarst(msg);
});
}
}
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: CvaDialogImportFileComponent, deps: [{ token: i1$1.MatDialogRef }, { token: ApiService }, { token: UtilsService }, { token: i1.TranslateService }, { token: MAT_DIALOG_DATA }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.5", type: CvaDialogImportFileComponent, isStandalone: false, selector: "cva-dialog-import-file", viewQueries: [{ propertyName: "inputFileRef", first: true, predicate: ["inputFile"], descendants: true }], ngImport: i0, template: `
<div>
<h2>{{'common.import.excel.' | translate}}</h2>
<div appDragDrop class="areaImportFile" (onFileDropped)="onDropped($event)"
(click)="onClickChooseFile(inputFile)">
<input class="d-zone" type="file"
#inputFile
(change)="onFileChange($event, inputFile)">
<span>
<i class="fal fa-plus mr-2"></i> {{'common.import.excel.drag.drop' | translate}}
</span>
</div>
<h4 style="width: 26rem">
{{file?.name}}
</h4>
<div class="but">
<button mat-button (click)="close()" type="button" class="primary outline">
{{'btnCancel' | translate}}
</button>
<button mat-button type="button" (click)="onImport()" class="primary">
{{'btnImport' | translate}}
</button>
<button mat-button *ngIf="errorImportExcelUrl" (click)="downloadErrorFile()" type="button"
class="danger">
{{'common.import.excel.download.error.file' | translate}}
</button>
</div>
<div class="download-template"><p>{{'common.import.excel.not.have.template' | translate}}</p><span
(click)="downloadTemplate()">{{'common.import.excel.download.template' | translate}}</span></div>
</div> `, isInline: true, styles: [":host{display:flex;flex-direction:column;justify-content:center;align-items:center;padding:0!important}h2,h4{margin:2rem;text-align:center}p{display:inline;text-align:center}span{color:#36f;cursor:pointer;text-align:center}.d-zone{display:none}.areaImportFile{width:26rem;height:10rem;border:1px dashed #3366FF;background:#fff!important;box-sizing:border-box;border-radius:10px;display:flex;justify-content:center;align-items:center;margin:2rem;cursor:pointer}.but{margin:2rem;display:flex;justify-content:center}.download-template{display:flex;justify-content:center;align-items:center}\n"], dependencies: [{ kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i3.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "directive", type: DragDropDirective, selector: "[appDragDrop]", outputs: ["onFileDropped"] }, { kind: "pipe", type: i1.TranslatePipe, name: "translate" }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: CvaDialogImportFileComponent, decorators: [{
type: Component,
args: [{ selector: 'cva-dialog-import-file', standalone: false, template: `
<div>
<h2>{{'common.import.excel.' | translate}}</h2>
<div appDragDrop class="areaImportFile" (onFileDropped)="onDropped($event)"
(click)="onClickChooseFile(inputFile)">
<input class="d-zone" type="file"
#inputFile
(change)="onFileChange($event, inputFile)">
<span>
<i class="fal fa-plus mr-2"></i> {{'common.import.excel.drag.drop' | translate}}
</span>
</div>
<h4 style="width: 26rem">
{{file?.name}}
</h4>
<div class="but">
<button mat-button (click)="close()" type="button" class="primary outline">
{{'btnCancel' | translate}}
</button>
<button mat-button type="button" (click)="onImport()" class="primary">
{{'btnImport' | translate}}
</button>
<button mat-button *ngIf="errorImportExcelUrl" (click)="downloadErrorFile()" type="button"
class="danger">
{{'common.import.excel.download.error.file' | translate}}
</button>
</div>
<div class="download-template"><p>{{'common.import.excel.not.have.template' | translate}}</p><span
(click)="downloadTemplate()">{{'common.import.excel.download.template' | translate}}</span></div>
</div> `, styles: [":host{display:flex;flex-direction:column;justify-content:center;align-items:center;padding:0!important}h2,h4{margin:2rem;text-align:center}p{display:inline;text-align:center}span{color:#36f;cursor:pointer;text-align:center}.d-zone{display:none}.areaImportFile{width:26rem;height:10rem;border:1px dashed #3366FF;background:#fff!important;box-sizing:border-box;border-radius:10px;display:flex;justify-content:center;align-items:center;margin:2rem;cursor:pointer}.but{margin:2rem;display:flex;justify-content:center}.download-template{display:flex;justify-content:center;align-items:center}\n"] }]
}], ctorParameters: () => [{ type: i1$1.MatDialogRef }, { type: ApiService }, { type: UtilsService }, { type: i1.TranslateService }, { type: DialogImportFileConfigModel, decorators: [{
type: Inject,
args: [MAT_DIALOG_DATA]
}] }], propDecorators: { inputFileRef: [{
type: ViewChild,
args: ['inputFile', { static: false }]
}] } });
class CvaQuillEditorComponent {
injector;
label = '';
name = '';
placeholder = '';
hint = '';
required = false;
disabled = false;
text = '';
textCounter = 0;
quillStyle;
// nếu cho vào base thì define rõ ràng, default check valid only text
quillModule = undefined;
onlyCheckTextValidation = true;
format = 'html';
pattern = null;
readonly = false;
errorMessages = new Map();
onChange = new EventEmitter();
multiline = false;
isLabelOutside = false;
isFloatLabel = true;
minLength;
maxLength;
maxSize; // don vi byte
minSize; // don vi byte
onFocusStatus = false;
/* hiển thị suffix thay maxlength */
maxLengthDisplay;
// Chỉ bằng false khi trong NsSmartTable thôi nhé @@
isFormControl = true;
formatFunc;
control = undefined;
get NsValidator() {
return ValidatorService;
}
constructor(injector, ngControl) {
this.injector = injector;
if (ngControl) {
// Hành động này thay cho provide: NG_VALUE_ACCESSOR và gắn ControlValueAccessor này vào parent FormControl
ngControl.valueAccessor = this;
}
}
ngOnInit() {
this.callValidator();
}
get textValue() {
return this.text;
}
set textValue(val) {
this.writeValue(val);
}
customLengthValidator = (control) => {
let length = 0;
if (!this.onlyCheckTextValidation) {
const description = control?.value ? control?.value : '';
length = new Blob([description]).size;
}
else {
length = this.textCounter;
}
if (!!this.minLength && length < this.minLength) {
return {
minlength: {
min: this.minLength,
actual: length
}
};
}
if (!!this.maxLength && length > this.maxLength) {
return {
maxlength: {
max: this.maxLength,
actual: length
}
};
}
return null;
};
customSizeValidator = (control) => {
let size = 0;
const description = control?.value ? control?.value : '';
size = new Blob([description]).size;
if (!!this.minSize && size < this.minSize) {
return {
minsize: {
min: this.minSize,
actual: size
}
};
}
if (!!this.maxSize && size > this.maxSize) {
return {
maxsize: {
max: this.maxSize,
actual: size
}
};
}
return null;
};
callValidator() {
const ngControl = this.injector.get(NgControl);
// Nếu parent FormControl khởi tạo xong và formControl chưa có giá trị lưu
if (ngControl && !this.control) {
// Nếu là NsSmartTable thì phải tự new FormControl còn không thì cứ hóng parent FormControl về ^^
if (this.isFormControl) {
this.control = ngControl.control ? ngControl.control : undefined;
}
else {
this.control = new FormControl();
}
// Hành động này gắn validator vào this.formControl
// - Nếu this.formControl là parent FormControl thì sẽ show error lên FormGroup
// - Nếu this.formControl là new FormControl thì sẽ quét QueryList để check {errors}
if (this.control) {
if (this.control.validator) {
this.control.setValidators([...ValidatorService.generateNsInputValidators({
required: this.required,
minLength: undefined,
maxLength: undefined,
pattern: this.pattern,
}), this.control.validator, this.customLengthValidator, this.customSizeValidator]);
}
else {
this.control.setValidators([...ValidatorService.generateNsInputValidators({
required: this.required,
minLength: undefined,
maxLength: undefined,
pattern: this.pattern,
}), this.customLengthValidator, this.customSizeValidator]);
}
}
}
if (this.control) {
// Nếu this.formControl thuộc NsSmartTable thì setValue lại
if (!this.isFormControl) {
this.control.setValue(this.text);
}
// Nếu là parent FormControl rồi thì kệ
this.control.updateValueAndValidity();
}
}
propagateChange = (_) => {
/*NON-EMPTY FOR COMPILE*/
};
/**
* Write a new value to the element.
*/
writeValue(obj) {
this.text = obj;
this.propagateChange(this.text);
this.callValidator();
this.onChange.emit(this.text);
}
/**
* Set the function to be called
* when the formControl receives a change event.
*/
registerOnChange(fn) {
this.propagateChange = fn;
}
/**
* Set the function to be called
* when the formControl receives a touch event.
*/
registerOnTouched() {
/*NON-EMPTY FOR COMPILE*/
}
displayLength() {
if (this.maxLength === null || this.maxLength === undefined) {
return this.maxLengthDisplay ? this.maxLengthDisplay : '';
}
return (this.textValue?.length ? this.textValue.length : 0) + '/' + this.getMaxLength();
}
getMaxLength() {
return this.maxLengthDisplay ? this.maxLengthDisplay : this.maxLength;
}
onFocus(event) {
this.onFocusStatus = true;
}
onBlur(event) {
if (this.onFocusStatus) {
this.onFocusStatus = false;
}
}
onChangeContent(quill, text) {
if (!text.html) {
this.textCounter = 0;
}
else {
this.textCounter = quill.editorElem.innerText.length;
}
this.writeValue(this.text);
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: CvaQuillEditorComponent, deps: [{ token: i0.Injector }, { token: i1$2.NgControl, optional: true, self: true }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.5", type: CvaQuillEditorComponent, isStandalone: false, selector: "cva-quill-editor", inputs: { label: "label", name: "name", placeholder: "placeholder", hint: "hint", required: "required", disabled: "disabled", text: "text", quillStyle: "quillStyle", quillModule: "quillModule", onlyCheckTextValidation: "onlyCheckTextValidation", format: "format", pattern: "pattern", readonly: "readonly", errorMessages: "errorMessages", multiline: "multiline", isLabelOutside: "isLabelOutside", isFloatLabel: "isFloatLabel", minLength: "minLength", maxLength: "maxLength", maxSize: "maxSize", minSize: "minSize", maxLengthDisplay: "maxLengthDisplay", isFormControl: "isFormControl", formatFunc: "formatFunc" }, outputs: { onChange: "onChange" }, ngImport: i0, template: `
<!-- css labelOutside trong base.theme-->
<div class="cva-quill-editor"
[ngClass]="{'labelOutside': !!isLabelOutside,
'float_label': !!isFloatLabel && !isLabelOutside,
'text_area': !!this.multiline}"
fxLayout="row" fxLayout.lt-sm="row wrap">
<mat-label *ngIf="isLabelOutside" class="label_width"
fxLayout="column" fxFlex="auto" fxFlex.lt-md="100%">
<div class="label">
<div>
{{(label ? label : '') | translate}}<span
class="required-label-outside">{{!!required ? '*' : ''}}</span>
</div>
</div>
</mat-label>
<div class="editor" fxLayout="column" fxFlex="100%">
<quill-editor [(ngModel)]="textValue"
[modules]="quillModule"
[disabled]="disabled"
[readOnly]="readonly"
[maxLength]="maxLength"
[minLength]="minLength"
[placeholder]="placeholder | translate"
[format]="format"
(onFocus)="onFocus($event)"
(onBlur)="onBlur($event)"
#quill [ngStyle]="quillStyle"
(onContentChanged)="onChangeContent(quill, $event)"
fxFlex="100%" fxFlex.lt-md="100%"
></quill-editor>
<div id="counter"
*ngIf="!(disabled || readonly) && onFocusStatus && !!maxLength">{{textCounter + '/' + maxLength}}</div>
<mat-hint align="start" *ngIf="!NsValidator.invalid(control)">{{hint | translate}}</mat-hint>
<mat-hint style="color: red" align="start" *ngIf="NsValidator.invalid(control)">
{{NsValidator.getErrorMessageV1(control, errorMessages).msg | translate: NsValidator.getErrorMessageV1(control, errorMessages).params}}
</mat-hint>
</div>
</div>
`, isInline: true, styles: [".cva-quill-editor{margin-bottom:1rem}.cva-quill-editor .required-label-outside{color:red}.cva-quill-editor .ql-container.ql-snow{height:100px;overflow-y:auto}.cva-quill-editor #counter{border:1px solid #ccc;border-width:0px 1px 1px 1px;color:#aaa;padding:5px 15px;text-align:right}.cva-quill-editor quill-editor{margin-bottom:0!important;word-break:break-word}\n"], dependencies: [{ kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i6.MatLabel, selector: "mat-label" }, { kind: "directive", type: i6.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "component", type: i4$4.QuillEditorComponent, selector: "quill-editor" }, { kind: "directive", type: i8.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { kind: "directive", type: i8.DefaultFlexDirective, selector: " [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]", inputs: ["fxFlex", "fxFlex.xs", "fxFlex.sm", "fxFlex.md", "fxFlex.lg", "fxFlex.xl", "fxFlex.lt-sm", "fxFlex.lt-md", "fxFlex.lt-lg", "fxFlex.lt-xl", "fxFlex.gt-xs", "fxFlex.gt-sm", "fxFlex.gt-md", "fxFlex.gt-lg"] }, { kind: "directive", type: i9.DefaultClassDirective, selector: " [ngClass], [ngClass.xs], [ngClass.sm], [ngClass.md], [ngClass.lg], [ngClass.xl], [ngClass.lt-sm], [ngClass.lt-md], [ngClass.lt-lg], [ngClass.lt-xl], [ngClass.gt-xs], [ngClass.gt-sm], [ngClass.gt-md], [ngClass.gt-lg]", inputs: ["ngClass", "ngClass.xs", "ngClass.sm", "ngClass.md", "ngClass.lg", "ngClass.xl", "ngClass.lt-sm", "ngClass.lt-md", "ngClass.lt-lg", "ngClass.lt-xl", "ngClass.gt-xs", "ngClass.gt-sm", "ngClass.gt-md", "ngClass.gt-lg"] }, { kind: "directive", type: i9.DefaultStyleDirective, selector: " [ngStyle], [ngStyle.xs], [ngStyle.sm], [ngStyle.md], [ngStyle.lg], [ngStyle.xl], [ngStyle.lt-sm], [ngStyle.lt-md], [ngStyle.lt-lg], [ngStyle.lt-xl], [ngStyle.gt-xs], [ngStyle.gt-sm], [ngStyle.gt-md], [ngStyle.gt-lg]", inputs: ["ngStyle", "ngStyle.xs", "ngStyle.sm", "ngStyle.md", "ngStyle.lg", "ngStyle.xl", "ngStyle.lt-sm", "ngStyle.lt-md", "ngStyle.lt-lg", "ngStyle.lt-xl", "ngStyle.gt-xs", "ngStyle.gt-sm", "ngStyle.gt-md", "ngStyle.gt-lg"] }, { kind: "pipe", type: i1.TranslatePipe, name: "translate" }], encapsulation: i0.ViewEncapsulation.None });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: CvaQuillEditorComponent, decorators: [{
type: Component,
args: [{ selector: 'cva-quill-editor', standalone: false, template: `
<!-- css labelOutside trong base.theme-->
<div class="cva-quill-editor"
[ngClass]="{'labelOutside': !!isLabelOutside,
'float_label': !!isFloatLabel && !isLabelOutside,
'text_area': !!this.multiline}"
fxLayout="row" fxLayout.lt-sm="row wrap">
<mat-label *ngIf="isLabelOutside" class="label_width"
fxLayout="column" fxFlex="auto" fxFlex.lt-md="100%">
<div class="label">
<div>
{{(label ? label : '') | translate}}<span
class="required-label-outside">{{!!required ? '*' : ''}}</span>
</div>
</div>
</mat-label>
<div class="editor" fxLayout="column" fxFlex="100%">
<quill-editor [(ngModel)]="textValue"
[modules]="quillModule"
[disabled]="disabled"
[readOnly]="readonly"
[maxLength]="maxLength"
[minLength]="minLength"
[placeholder]="placeholder | translate"
[format]="format"
(onFocus)="onFocus($event)"
(onBlur)="onBlur($event)"
#quill [ngStyle]="quillStyle"
(onContentChanged)="onChangeContent(quill, $event)"
fxFlex="100%" fxFlex.lt-md="100%"
></quill-editor>
<div id="counter"
*ngIf="!(disabled || readonly) && onFocusStatus && !!maxLength">{{textCounter + '/' + maxLength}}</div>
<mat-hint align="start" *ngIf="!NsValidator.invalid(control)">{{hint | translate}}</mat-hint>
<mat-hint style="color: red" align="start" *ngIf="NsValidator.invalid(control)">
{{NsValidator.getErrorMessageV1(control, errorMessages).msg | translate: NsValidator.getErrorMessageV1(control, errorMessages).params}}
</mat-hint>
</div>
</div>
`, encapsulation: ViewEncapsulation.None, styles: [".cva-quill-editor{margin-bottom:1rem}.cva-quill-editor .required-label-outside{color:red}.cva-quill-editor .ql-container.ql-snow{height:100px;overflow-y:auto}.cva-quill-editor #counter{border:1px solid #ccc;border-width:0px 1px 1px 1px;color:#aaa;padding:5px 15px;text-align:right}.cva-quill-editor quill-editor{margin-bottom:0!important;word-break:break-word}\n"] }]
}], ctorParameters: () => [{ type: i0.Injector }, { type: i1$2.NgControl, decorators: [{
type: Self
}, {
type: Optional
}] }], propDecorators: { label: [{
type: Input
}], name: [{
type: Input
}], placeholder: [{
type: Input
}], hint: [{
type: Input
}], required: [{
type: Input
}], disabled: [{
type: Input
}], text: [{
type: Input
}], quillStyle: [{
type: Input
}], quillModule: [{
type: Input
}], onlyCheckTextValidation: [{
type: Input
}], format: [{
type: Input
}], pattern: [{
type: Input
}], readonly: [{
type: Input
}], errorMessages: [{
type: Input
}], onChange: [{
type: Output
}], multiline: [{
type: Input
}], isLabelOutside: [{
type: Input
}], isFloatLabel: [{
type: Input
}], minLength: [{
type: Input
}], maxLength: [{
type: Input
}], maxSize: [{
type: Input
}], minSize: [{
type: Input
}], maxLengthDisplay: [{
type: Input
}], isFormControl: [{
type: Input
}], formatFunc: [{
type: Input
}] } });
class JsogHttpInterceptor {
jSog;
constructor(jSog) {
this.jSog = jSog;
}
intercept(request, next) {
if (request.body && !(request.body instanceof FormData)) {
request = request.clone({ body: this.jSog.serialize(request.body) });
}
return next.handle(request).pipe(map((event) => {
if (!(event instanceof HttpResponse || HttpResponseBase.prototype.isPrototypeOf(event))) {
return event;
}
let response = event;
if (!response.body || typeof (response.body) !== 'object' || (response.body instanceof Blob)) {
return response;
}
response = response.clone({ body: this.jSog.deserializeArray(response.body, BaseModel) });
return response;
}));
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: JsogHttpInterceptor, deps: [{ token: i1$6.JsogService }], target: i0.ɵɵFactoryTarget.Injectable });
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: JsogHttpInterceptor, providedIn: 'root' });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: JsogHttpInterceptor, decorators: [{
type: Injectable,
args: [{ providedIn: 'root' }]
}], ctorParameters: () => [{ type: i1$6.JsogService }] });
class LoaderInterceptor {
loaderService;
requests = [];
constructor(loaderService) {
this.loaderService = loaderService;
}
removeRequest(req) {
const i = this.requests.indexOf(req);
if (i >= 0) {
this.requests.splice(i, 1);
}
this.loaderService.isLoading.next(this.requests.length > 0);
}
intercept(request, next) {
if (!request.headers.get('is_image') && !request.headers.get('is_live_searching')) {
this.requests.push(request);
this.loaderService.isLoading.next(true);
}
else {
request = request.clone({
headers: request.headers.delete('is_image').delete('is_live_searching'),
});
}
return next.handle(request).pipe(map((event) => {
if (event instanceof HttpResponse) {
this.removeRequest(request);
}
return event;
}), catchError(err => {
console.error('Error: ', err);
this.removeRequest(request);
return throwError(err);
}), finalize(() => {
this.removeRequest(request);
}));
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: LoaderInterceptor, deps: [{ token: LoaderService }], target: i0.ɵɵFactoryTarget.Injectable });
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: LoaderInterceptor, providedIn: 'root' });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: LoaderInterceptor, decorators: [{
type: Injectable,
args: [{ providedIn: 'root' }]
}], ctorParameters: () => [{ type: LoaderService }] });
class AuthoritiesResolverService {
authoritiesService;
injector;
apiService;
config;
constructor(authoritiesService, injector, apiService) {
this.authoritiesService = authoritiesService;
this.injector = injector;
this.apiService = apiService;
this.config = injector.get(InjectTokenNextSolutionsConfig);
}
resolve(route, state) {
return !!this.authoritiesService.me && !!this.authoritiesService.me.userAuthentication ? of(this.authoritiesService.me)
: this.apiService.get('/user/me', new HttpParams(), this.config.BASE_AUTHORIZATION_URL);
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: AuthoritiesResolverService, deps: [{ token: AuthoritiesService }, { token: i0.Injector }, { token: ApiService }], target: i0.ɵɵFactoryTarget.Injectable });
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: AuthoritiesResolverService, providedIn: 'root' });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: AuthoritiesResolverService, decorators: [{
type: Injectable,
args: [{ providedIn: 'root' }]
}], ctorParameters: () => [{ type: AuthoritiesService }, { type: i0.Injector }, { type: ApiService }] });
class SingletonTranslateService {
currentLanguage = new BehaviorSubject('');
currentLanguage$ = this.currentLanguage.asObservable();
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: SingletonTranslateService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: SingletonTranslateService, providedIn: 'root' });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: SingletonTranslateService, decorators: [{
type: Injectable,
args: [{ providedIn: 'root' }]
}] });
const MATERIAL_MODULES = [
MatAutocompleteModule,
MatButtonModule,
MatButtonToggleModule,
MatCardModule,
MatChipsModule,
MatCheckboxModule,
MatDatepickerModule,
MatTableModule,
MatDialogModule,
MatFormFieldModule,
MatGridListModule,
MatIconModule,
MatInputModule,
MatListModule,
MatMenuModule,
MatPaginatorModule,
MatProgressBarModule,
MatProgressSpinnerModule,
MatRippleModule,
MatSelectModule,
MatSidenavModule,
MatSliderModule,
MatSlideToggleModule,
MatSnackBarModule,
MatSortModule,
MatStepperModule,
MatTabsModule,
MatToolbarModule,
MatTooltipModule,
MatTreeModule,
OverlayModule,
PortalModule,
BidiModule,
A11yModule,
MatCommonModule,
ObserversModule,
MatRadioModule,
ScrollingModule,
ScrollingModule$1,
CdkTreeModule,
];
class AngularMaterialModule {
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: AngularMaterialModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.1.5", ngImport: i0, type: AngularMaterialModule, imports: [MatAutocompleteModule,
MatButtonModule,
MatButtonToggleModule,
MatCardModule,
MatChipsModule,
MatCheckboxModule,
MatDatepickerModule,
MatTableModule,
MatDialogModule,
MatFormFieldModule,
MatGridListModule,
MatIconModule,
MatInputModule,
MatListModule,
MatMenuModule,
MatPaginatorModule,
MatProgressBarModule,
MatProgressSpinnerModule,
MatRippleModule,
MatSelectModule,
MatSidenavModule,
MatSliderModule,
MatSlideToggleModule,
MatSnackBarModule,
MatSortModule,
MatStepperModule,
MatTabsModule,
MatToolbarModule,
MatTooltipModule,
MatTreeModule,
OverlayModule,
PortalModule,
BidiModule,
A11yModule,
MatCommonModule,
ObserversModule,
MatRadioModule,
ScrollingModule,
ScrollingModule$1,
CdkTreeModule], exports: [MatAutocompleteModule,
MatButtonModule,
MatButtonToggleModule,
MatCardModule,
MatChipsModule,
MatCheckboxModule,
MatDatepickerModule,
MatTableModule,
MatDialogModule,
MatFormFieldModule,
MatGridListModule,
MatIconModule,
MatInputModule,
MatListModule,
MatMenuModule,
MatPaginatorModule,
MatProgressBarModule,
MatProgressSpinnerModule,
MatRippleModule,
MatSelectModule,
MatSidenavModule,
MatSliderModule,
MatSlideToggleModule,
MatSnackBarModule,
MatSortModule,
MatStepperModule,
MatTabsModule,
MatToolbarModule,
MatTooltipModule,
MatTreeModule,
OverlayModule,
PortalModule,
BidiModule,
A11yModule,
MatCommonModule,
ObserversModule,
MatRadioModule,
ScrollingModule,
ScrollingModule$1,
CdkTreeModule] });
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: AngularMaterialModule, providers: [
CdkTree,
CdkTreeNode,
], imports: [MATERIAL_MODULES, MatAutocompleteModule,
MatButtonModule,
MatButtonToggleModule,
MatCardModule,
MatChipsModule,
MatCheckboxModule,
MatDatepickerModule,
MatTableModule,
MatDialogModule,
MatFormFieldModule,
MatGridListModule,
MatIconModule,
MatInputModule,
MatListModule,
MatMenuModule,
MatPaginatorModule,
MatProgressBarModule,
MatProgressSpinnerModule,
MatRippleModule,
MatSelectModule,
MatSidenavModule,
MatSliderModule,
MatSlideToggleModule,
MatSnackBarModule,
MatSortModule,
MatStepperModule,
MatTabsModule,
MatToolbarModule,
MatTooltipModule,
MatTreeModule,
OverlayModule,
PortalModule,
BidiModule,
A11yModule,
MatCommonModule,
ObserversModule,
MatRadioModule,
ScrollingModule,
ScrollingModule$1,
CdkTreeModule] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: AngularMaterialModule, decorators: [{
type: NgModule,
args: [{
imports: MATERIAL_MODULES,
exports: MATERIAL_MODULES,
providers: [
CdkTree,
CdkTreeNode,
],
}]
}] });
// @dynamic
class NiceComponentLibraryModule {
static forRoot(config) {
return {
ngModule: NiceComponentLibraryModule,
providers: [
ApiService, DateUtilService, FormStateService, UtilsService, LoaderService, ValidatorService,
AuthoritiesService, AuthoritiesResolverService, SingletonTranslateService,
{ provide: InjectTokenNextSolutionsConfig, useValue: config ? config.data : {} }
],
};
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: NiceComponentLibraryModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.1.5", ngImport: i0, type: NiceComponentLibraryModule, declarations: [CvaTableComponent,
CvaSmartTableComponent,
CvaInputComponent,
CvaCounterInputComponent,
CvaDatePickerComponent,
CvaRangeDatePickerComponent,
CvaMultiSelectAutocomplete,
DragDropDirective,
CvaMultiUploadComponent,
CvaUploadFileComponent,
CvaMultiUploadImgComponent,
CvaBreadcrumbComponent,
CvaLoaderComponent,
CvaTreeComponent,
CvaCustomDialogComponent,
CvaRadiobuttonComponent,
StylePaginatorDirective,
SecureImgPipe,
CvaFlatTreeComponent,
CvaFlatTreeNodeLeftComponent,
CvaFlatTreeNodeRightComponent,
CvaHeaderExpandButtonComponent,
PatternDirective,
FormatInputDirective,
CvaDialogImportFileComponent,
BaseSearchComponent,
BaseAddEditComponent,
CvaQuillEditorComponent,
CvaLiveSearchingComponent], imports: [CommonModule,
FormsModule,
ReactiveFormsModule,
AngularMaterialModule, i1$4.RouterModule, i1.TranslateModule, i4$4.QuillModule, FlexLayoutModule], exports: [CvaTableComponent,
CvaSmartTableComponent,
CvaInputComponent,
CvaCounterInputComponent,
CvaDatePickerComponent,
CvaRangeDatePickerComponent,
CvaMultiSelectAutocomplete,
DragDropDirective,
CvaMultiUploadComponent,
CvaUploadFileComponent,
CvaMultiUploadImgComponent,
CvaBreadcrumbComponent,
CvaLoaderComponent,
CvaTreeComponent,
CvaCustomDialogComponent,
CvaRadiobuttonComponent,
StylePaginatorDirective,
CvaFlatTreeComponent,
SecureImgPipe,
PatternDirective,
FormatInputDirective,
CvaFlatTreeNodeLeftComponent,
CvaFlatTreeNodeRightComponent,
CvaDialogImportFileComponent,
BaseSearchComponent,
BaseAddEditComponent,
CvaQuillEditorComponent,
CvaLiveSearchingComponent] });
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: NiceComponentLibraryModule, imports: [CommonModule,
FormsModule,
ReactiveFormsModule,
AngularMaterialModule,
RouterModule.forChild([]),
TranslateModule.forChild(),
QuillModule.forRoot(),
FlexLayoutModule] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: NiceComponentLibraryModule, decorators: [{
type: NgModule,
args: [{
imports: [
CommonModule,
FormsModule,
ReactiveFormsModule,
AngularMaterialModule,
RouterModule.forChild([]),
TranslateModule.forChild(),
QuillModule.forRoot(),
FlexLayoutModule,
],
declarations: [
CvaTableComponent,
CvaSmartTableComponent,
CvaInputComponent,
CvaCounterInputComponent,
CvaDatePickerComponent,
CvaRangeDatePickerComponent,
CvaMultiSelectAutocomplete,
DragDropDirective,
CvaMultiUploadComponent,
CvaUploadFileComponent,
CvaMultiUploadImgComponent,
CvaBreadcrumbComponent,
CvaLoaderComponent,
CvaTreeComponent,
CvaCustomDialogComponent,
CvaRadiobuttonComponent,
StylePaginatorDirective,
SecureImgPipe,
CvaFlatTreeComponent,
CvaFlatTreeNodeLeftComponent,
CvaFlatTreeNodeRightComponent,
CvaHeaderExpandButtonComponent,
PatternDirective,
FormatInputDirective,
CvaDialogImportFileComponent,
BaseSearchComponent,
BaseAddEditComponent,
CvaQuillEditorComponent,
CvaLiveSearchingComponent,
],
exports: [
CvaTableComponent,
CvaSmartTableComponent,
CvaInputComponent,
CvaCounterInputComponent,
CvaDatePickerComponent,
CvaRangeDatePickerComponent,
CvaMultiSelectAutocomplete,
DragDropDirective,
CvaMultiUploadComponent,
CvaUploadFileComponent,
CvaMultiUploadImgComponent,
CvaBreadcrumbComponent,
CvaLoaderComponent,
CvaTreeComponent,
CvaCustomDialogComponent,
CvaRadiobuttonComponent,
StylePaginatorDirective,
CvaFlatTreeComponent,
SecureImgPipe,
PatternDirective,
FormatInputDirective,
CvaFlatTreeNodeLeftComponent,
CvaFlatTreeNodeRightComponent,
CvaDialogImportFileComponent,
BaseSearchComponent,
BaseAddEditComponent,
CvaQuillEditorComponent,
CvaLiveSearchingComponent,
],
schemas: [
NO_ERRORS_SCHEMA,
CUSTOM_ELEMENTS_SCHEMA,
],
}]
}] });
/*
* Các cháu này là base class
* */
/**
* Generated bundle index. Do not edit.
*/
export { ActionTypeEnum, AlignEnum, ApiService, AuthoritiesResolverService, AuthoritiesService, Authority, BaseAddEditComponent, BaseModel, BaseSearchComponent, BaseStatusEnum, BaseTableComponent, BreadCrumbModel, ButtonClickEvent, ButtonModel, CheckboxModel, ColumnModel, ColumnTypeEnum, CustomDialogDataConfigModel, CvaBreadcrumbComponent, CvaCounterInputComponent, CvaCustomDialogComponent, CvaDatePickerComponent, CvaDialogImportFileComponent, CvaFlatTreeComponent, CvaFlatTreeNodeLeftComponent, CvaFlatTreeNodeRightComponent, CvaInputComponent, CvaLiveSearchingComponent, CvaLoaderComponent, CvaMultiSelectAutocomplete, CvaMultiUploadComponent, CvaMultiUploadImgComponent, CvaQuillEditorComponent, CvaRadiobuttonComponent, CvaRangeDatePickerComponent, CvaSmartTableComponent, CvaTableComponent, CvaTreeComponent, CvaUploadFileComponent, DateUtilService, DialogImportFileConfigModel, DialogTypeEnum, DragDropDirective, FileTypeEnum, FlatTreeConfigModel, FlatTreeModel, FlatTreeNodeModel, FormStateService, FormatInputDirective, IconTypeEnum, InjectTokenNextSolutionsConfig, JsogHttpInterceptor, LoaderInterceptor, LoaderService, MenuModel, MultiTranslateHttpLoader, NavigatorModel, NiceComponentLibraryModule, OAuth2AuthenticationDto, PatternDirective, PermissionModel, Principal, RangeDatePickerModel, RoleModel, SecureImgPipe, SelectModel, SingletonTranslateService, StylePaginatorDirective, TableFooterModel, TablePagingRequestModel, TablePagingResponseModel, TableService, UIState, UploadModel, UtilsService, ValidatorService };
//# sourceMappingURL=c10t-nice-component-library.mjs.map