mirror of
https://github.com/SuiteCRM/SuiteCRM-Core.git
synced 2025-08-29 08:17:18 +08:00
Change ngx-chips with primeng multiselect
This commit is contained in:
parent
0855cb18a2
commit
4795d38da5
19 changed files with 251 additions and 119 deletions
|
@ -26,7 +26,9 @@
|
|||
],
|
||||
"styles": [
|
||||
"node_modules/bootstrap-css-only/css/bootstrap.min.css",
|
||||
"core/app/shell/src/themes/suite8/css/style.scss"
|
||||
"core/app/shell/src/themes/suite8/css/style.scss",
|
||||
"node_modules/primeng/resources/themes/lara-light-blue/theme.css",
|
||||
"node_modules/primeng/resources/primeng.min.css"
|
||||
],
|
||||
"stylePreprocessorOptions": {
|
||||
"includePaths": [
|
||||
|
@ -359,6 +361,7 @@
|
|||
}
|
||||
},
|
||||
"cli": {
|
||||
"packageManager": "yarn"
|
||||
"packageManager": "yarn",
|
||||
"analytics": false
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,6 +38,12 @@ parameters:
|
|||
listview_max_height: 0
|
||||
record_modal_max_height: 620
|
||||
inline_confirmation_loading_delay: 300
|
||||
multiselect_max_number:
|
||||
XSmall: 2
|
||||
Small: 2
|
||||
Medium: 4
|
||||
Large: 20
|
||||
XLarge: 20
|
||||
displayed_quick_filters:
|
||||
XSmall: 0
|
||||
Small: 4
|
||||
|
|
|
@ -205,7 +205,7 @@ export class SavedFilterStore implements StateStore {
|
|||
}
|
||||
|
||||
initValidators(record: Record): void {
|
||||
if(!record || !Object.keys(record?.fields).length) {
|
||||
if(!record || !record?.fields || !Object.keys(record?.fields).length) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@ import {
|
|||
} from '../../store/language/language.store';
|
||||
import {FieldLogicManager} from '../field-logic/field-logic.manager';
|
||||
import {FieldLogicDisplayManager} from '../field-logic-display/field-logic-display.manager';
|
||||
import {isNull, isObject} from "lodash-es";
|
||||
|
||||
@Component({template: ''})
|
||||
export class BaseEnumComponent extends BaseFieldComponent implements OnInit, OnDestroy {
|
||||
|
@ -150,6 +151,10 @@ export class BaseEnumComponent extends BaseFieldComponent implements OnInit, OnD
|
|||
this.options = [];
|
||||
Object.keys(this.optionsMap).forEach(key => {
|
||||
|
||||
if(isEmptyString(this.optionsMap[key]) && this.field.type === 'multienum') {
|
||||
return;
|
||||
}
|
||||
|
||||
this.options.push({
|
||||
value: key,
|
||||
label: this.optionsMap[key]
|
||||
|
@ -209,8 +214,7 @@ export class BaseEnumComponent extends BaseFieldComponent implements OnInit, OnD
|
|||
* */
|
||||
protected initEnumDefault(): void {
|
||||
|
||||
if (!isEmptyString(this.record?.id)) {
|
||||
|
||||
if (!isEmptyString(this.record?.id)) {
|
||||
this.field?.formControl.setValue('');
|
||||
|
||||
return;
|
||||
|
@ -224,12 +228,10 @@ export class BaseEnumComponent extends BaseFieldComponent implements OnInit, OnD
|
|||
this.field.formControl.setValue('');
|
||||
return;
|
||||
}
|
||||
|
||||
this.selectedValues.push({
|
||||
value: defaultVal,
|
||||
label: this.optionsMap[defaultVal]
|
||||
});
|
||||
|
||||
this.initEnumDefaultFieldValues(defaultVal);
|
||||
}
|
||||
|
||||
|
@ -335,4 +337,22 @@ export class BaseEnumComponent extends BaseFieldComponent implements OnInit, OnD
|
|||
}
|
||||
}
|
||||
|
||||
protected buildOptionFromValue(value: string): Option {
|
||||
const option: Option = {value: '', label: ''};
|
||||
|
||||
if (isNull(value)) {
|
||||
return option;
|
||||
}
|
||||
option.value = (typeof value !== 'string' ? JSON.stringify(value) : value).trim();
|
||||
option.label = option.value;
|
||||
|
||||
const valueLabel = this.optionsMap[option.value] ?? option.label;
|
||||
if (isObject(valueLabel)) {
|
||||
return option;
|
||||
}
|
||||
option.label = (typeof valueLabel !== 'string' ? JSON.stringify(valueLabel) : valueLabel).trim();
|
||||
|
||||
return option;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ import {DataTypeFormatter} from '../../services/formatters/data-type.formatter.s
|
|||
import {debounceTime} from 'rxjs/operators';
|
||||
import {FieldLogicManager} from '../field-logic/field-logic.manager';
|
||||
import {FieldLogicDisplayManager} from '../field-logic-display/field-logic-display.manager';
|
||||
import {isEqual} from "lodash-es";
|
||||
|
||||
@Component({template: ''})
|
||||
export class BaseFieldComponent implements FieldComponentInterface, OnInit, OnDestroy {
|
||||
|
@ -278,6 +279,15 @@ export class BaseFieldComponent implements FieldComponentInterface, OnInit, OnDe
|
|||
this.field.value = newValue;
|
||||
}
|
||||
|
||||
protected setFormControlValue(newValue: string | string[]): void {
|
||||
this.field.formControl.markAsDirty();
|
||||
|
||||
if (isEqual(this.field.formControl.value, newValue)) {
|
||||
return;
|
||||
}
|
||||
this.field.formControl.setValue(newValue);
|
||||
}
|
||||
|
||||
protected unsubscribeAll(): void {
|
||||
this.subs.forEach(sub => sub.unsubscribe());
|
||||
}
|
||||
|
|
|
@ -30,6 +30,8 @@ import {BaseEnumComponent} from './base-enum.component';
|
|||
import {LanguageStore} from '../../store/language/language.store';
|
||||
import {FieldLogicManager} from '../field-logic/field-logic.manager';
|
||||
import {FieldLogicDisplayManager} from '../field-logic-display/field-logic-display.manager';
|
||||
import { isArray, isEmpty, uniqBy } from 'lodash-es';
|
||||
import { isVoid } from 'common';
|
||||
|
||||
@Component({template: ''})
|
||||
export class BaseMultiEnumComponent extends BaseEnumComponent {
|
||||
|
@ -43,22 +45,42 @@ export class BaseMultiEnumComponent extends BaseEnumComponent {
|
|||
super(languages, typeFormatter, logic, logicDisplay);
|
||||
}
|
||||
|
||||
protected initValue(): void {
|
||||
this.selectedValues = [];
|
||||
protected subscribeValueChanges(): void {
|
||||
if (!this.field?.formControl) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.field.valueList || this.field.valueList.length < 1) {
|
||||
const formValueChangesSubscription = this.field.formControl.valueChanges.subscribe(
|
||||
(value: string[]) => this.field.valueList = value);
|
||||
|
||||
this.subs.push(formValueChangesSubscription);
|
||||
}
|
||||
|
||||
protected initValue(): void {
|
||||
const fieldValueList = this.field.valueList;
|
||||
|
||||
if (isVoid(fieldValueList) || isEmpty(fieldValueList)) {
|
||||
this.initEnumDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
this.field.valueList.forEach(value => {
|
||||
if (typeof this.optionsMap[value] !== 'string') {
|
||||
return;
|
||||
}
|
||||
this.selectedValues.push({
|
||||
value,
|
||||
label: this.optionsMap[value]
|
||||
});
|
||||
});
|
||||
this.updateInternalState(fieldValueList);
|
||||
}
|
||||
|
||||
protected updateInternalState(value: string | string[] = []): void {
|
||||
const valueArray = isArray(value) ? value : [value];
|
||||
|
||||
this.selectedValues = valueArray.map(valueElement=>this.buildOptionFromValue(valueElement));
|
||||
this.selectedValues = uniqBy(this.selectedValues, 'value');
|
||||
|
||||
this.syncSelectedValuesWithForm();
|
||||
}
|
||||
|
||||
protected syncSelectedValuesWithForm(): string[] {
|
||||
const selectedValuesValueMap = this.selectedValues.map(selectedValue => selectedValue.value);
|
||||
|
||||
this.setFormControlValue(selectedValuesValueMap);
|
||||
|
||||
return selectedValuesValueMap;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ import {FieldLogicDisplayManager} from '../field-logic-display/field-logic-displ
|
|||
@Component({template: ''})
|
||||
export class BaseRelateComponent extends BaseFieldComponent implements OnInit, OnDestroy {
|
||||
selectedValues: AttributeMap[] = [];
|
||||
options: AttributeMap[] = [];
|
||||
|
||||
status: '' | 'searching' | 'not-found' | 'error' | 'found' | 'no-module' = '';
|
||||
initModule = '';
|
||||
|
@ -79,7 +80,6 @@ export class BaseRelateComponent extends BaseFieldComponent implements OnInit, O
|
|||
}
|
||||
|
||||
onModuleChange(): void {
|
||||
|
||||
const currentModule = this.initModule;
|
||||
const newModule = this?.field?.definition?.module ?? '';
|
||||
|
||||
|
@ -96,12 +96,20 @@ export class BaseRelateComponent extends BaseFieldComponent implements OnInit, O
|
|||
if (newModule === '') {
|
||||
this.status = 'no-module';
|
||||
} else {
|
||||
this.init();
|
||||
this.status = '';
|
||||
this.selectedValues = [];
|
||||
this.options = [];
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
search = (text: string): Observable<any> => {
|
||||
|
||||
if(text === '') {
|
||||
return of([]);
|
||||
}
|
||||
|
||||
this.status = 'searching';
|
||||
|
||||
return this.relateService.search(text, this.getRelateFieldName()).pipe(
|
||||
|
|
|
@ -26,13 +26,13 @@
|
|||
*/
|
||||
-->
|
||||
<div class="dropdownenum">
|
||||
<select [formControl]="field.formControl" class="custom-select custom-select-sm">
|
||||
<ng-container *ngIf="this.options && this.options.length">
|
||||
<ng-container *ngIf="this.options && this.options.length">
|
||||
<select [formControl]="field.formControl" class="custom-select custom-select-sm">
|
||||
<option *ngFor="let item of this.options;"
|
||||
class="{{getId(item)}}"
|
||||
[ngValue]="item.value">
|
||||
{{item.label}}
|
||||
</option>
|
||||
</ng-container>
|
||||
</select>
|
||||
</select>
|
||||
</ng-container>
|
||||
</div>
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
import {Injectable} from '@angular/core';
|
||||
import {BaseActionManager} from '../../services/actions/base-action-manager.service';
|
||||
import {FieldLogicActionData, FieldLogicActionHandlerMap} from './field-logic.action';
|
||||
import {Action, ActionContext, ActionHandlerMap, Field, ModeActions, Record, ViewMode} from 'common';
|
||||
import {Action, ActionContext, Field, ModeActions, Record, ViewMode} from 'common';
|
||||
import {FieldLogicDisplayTypeAction} from './display-type/field-logic-display-type.action';
|
||||
import {EmailPrimarySelectAction} from './email-primary-select/email-primary-select.action';
|
||||
import {RequiredAction} from './required/required.action';
|
||||
|
@ -37,7 +37,6 @@ import {UpdateFlexRelateModuleAction} from './update-flex-relate-module/update-f
|
|||
import {UpdateValueAction} from './update-value/update-value.action';
|
||||
import {UpdateValueBackendAction} from './update-value-backend/update-value-backend.action';
|
||||
import {DisplayTypeBackendAction} from './display-type-backend/display-type-backend.action';
|
||||
import {RecordActionData} from '../../views/record/actions/record.action';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
|
|
|
@ -25,22 +25,15 @@
|
|||
* the words "Supercharged by SuiteCRM".
|
||||
*/
|
||||
-->
|
||||
<tag-input [(ngModel)]="selectedValues"
|
||||
[onlyFromAutocomplete]="true"
|
||||
[clearOnBlur]="true"
|
||||
[displayBy]="'label'"
|
||||
[identifyBy]="'value'"
|
||||
[placeholder]="getPlaceholderLabel()"
|
||||
[secondaryPlaceholder]="getPlaceholderLabel()"
|
||||
[inputClass]="getInvalidClass()"
|
||||
#tag
|
||||
(onAdd)="onAdd()"
|
||||
(onRemove)="onRemove()"
|
||||
(keyup.enter)="selectFirstElement()">
|
||||
<tag-input-dropdown [displayBy]="'label'"
|
||||
[identifyBy]="'value'"
|
||||
[showDropdownIfEmpty]="true"
|
||||
[keepOpen]="false"
|
||||
[autocompleteItems]="this.options">
|
||||
</tag-input-dropdown>
|
||||
</tag-input>
|
||||
<p-multiSelect
|
||||
[options]="this.options"
|
||||
[(ngModel)]="selectedValues"
|
||||
[optionLabel]="'label'"
|
||||
(onChange)="onAdd($event)"
|
||||
(onRemove)="onRemove()"
|
||||
[placeholder]="placeholderLabel"
|
||||
[selectedItemsLabel]="'{0} ' + selectedItemsLabel"
|
||||
[emptyFilterMessage]="emptyFilterLabel"
|
||||
[maxSelectedLabels]="maxSelectedLabels"
|
||||
[styleClass]="getInvalidClass()"
|
||||
></p-multiSelect>
|
||||
|
|
|
@ -24,14 +24,15 @@
|
|||
* the words "Supercharged by SuiteCRM".
|
||||
*/
|
||||
|
||||
import {Component, ViewChild} from '@angular/core';
|
||||
import {TagInputComponent} from 'ngx-chips';
|
||||
import {Component} from '@angular/core';
|
||||
import {DataTypeFormatter} from '../../../../services/formatters/data-type.formatter.service';
|
||||
import {BaseMultiEnumComponent} from '../../../base/base-multienum.component';
|
||||
import {LanguageStore} from '../../../../store/language/language.store';
|
||||
import {TagModel} from 'ngx-chips/core/tag-model';
|
||||
import {FieldLogicManager} from '../../../field-logic/field-logic.manager';
|
||||
import {FieldLogicDisplayManager} from '../../../field-logic-display/field-logic-display.manager';
|
||||
import {ScreenSizeObserverService} from "../../../../services/ui/screen-size-observer/screen-size-observer.service";
|
||||
import {take} from "rxjs/operators";
|
||||
import {SystemConfigStore} from "../../../../store/system-config/system-config.store";
|
||||
|
||||
@Component({
|
||||
selector: 'scrm-multienum-edit',
|
||||
|
@ -40,29 +41,40 @@ import {FieldLogicDisplayManager} from '../../../field-logic-display/field-logic
|
|||
})
|
||||
export class MultiEnumEditFieldComponent extends BaseMultiEnumComponent {
|
||||
|
||||
@ViewChild('tag') tag: TagInputComponent;
|
||||
placeholderLabel: string = '';
|
||||
selectedItemsLabel: string = '';
|
||||
emptyFilterLabel: string = '';
|
||||
maxSelectedLabels: number = 20;
|
||||
|
||||
constructor(
|
||||
protected languages: LanguageStore,
|
||||
protected typeFormatter: DataTypeFormatter,
|
||||
protected logic: FieldLogicManager,
|
||||
protected logicDisplay: FieldLogicDisplayManager
|
||||
protected logicDisplay: FieldLogicDisplayManager,
|
||||
protected screenSize: ScreenSizeObserverService,
|
||||
protected systemConfigStore: SystemConfigStore,
|
||||
) {
|
||||
super(languages, typeFormatter, logic, logicDisplay);
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.checkAndInitAsDynamicEnum();
|
||||
this.getTranslatedLabels();
|
||||
super.ngOnInit();
|
||||
const maxSelectedLabelsForDisplay = this.systemConfigStore.getUi('multiselect_max_number');
|
||||
this.screenSize.screenSize$
|
||||
.pipe(take(1))
|
||||
.subscribe((screenSize: any) => {
|
||||
this.maxSelectedLabels = maxSelectedLabelsForDisplay[screenSize] || this.maxSelectedLabels;
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
public onAdd(): void {
|
||||
public onAdd(event): void {
|
||||
const value = this.selectedValues.map(option => option.value);
|
||||
this.field.valueList = value;
|
||||
this.field.formControl.setValue(value);
|
||||
this.field.formControl.markAsDirty();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
public onRemove(): void {
|
||||
|
@ -70,25 +82,12 @@ export class MultiEnumEditFieldComponent extends BaseMultiEnumComponent {
|
|||
this.field.valueList = value;
|
||||
this.field.formControl.setValue(value);
|
||||
this.field.formControl.markAsDirty();
|
||||
|
||||
setTimeout(() => {
|
||||
this.tag.focus(true, true);
|
||||
this.tag.dropdown.show();
|
||||
}, 200);
|
||||
}
|
||||
|
||||
public getPlaceholderLabel(): string {
|
||||
return this.languages.getAppString('LBL_SELECT_ITEM') || '';
|
||||
}
|
||||
|
||||
public selectFirstElement(): void {
|
||||
const filteredElements: TagModel = this.tag.dropdown.items;
|
||||
if (filteredElements.length !== 0) {
|
||||
const firstElement = filteredElements[0];
|
||||
this.selectedValues.push(firstElement);
|
||||
this.onAdd();
|
||||
this.tag.dropdown.hide();
|
||||
}
|
||||
public getTranslatedLabels(): void {
|
||||
this.placeholderLabel = this.languages.getAppString('LBL_SELECT_ITEM') || '';
|
||||
this.selectedItemsLabel = this.languages.getAppString('LBL_ITEMS_SELECTED') || '';
|
||||
this.emptyFilterLabel = this.languages.getAppString('ERR_SEARCH_NO_RESULTS') || '';
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -28,16 +28,16 @@ import {NgModule} from '@angular/core';
|
|||
import {CommonModule} from '@angular/common';
|
||||
|
||||
import {FormsModule} from '@angular/forms';
|
||||
import {TagInputModule} from 'ngx-chips';
|
||||
import {MultiEnumEditFieldComponent} from './multienum.component';
|
||||
import {MultiSelectModule} from "primeng/multiselect";
|
||||
|
||||
@NgModule({
|
||||
declarations: [MultiEnumEditFieldComponent],
|
||||
exports: [MultiEnumEditFieldComponent],
|
||||
imports: [
|
||||
CommonModule,
|
||||
TagInputModule,
|
||||
FormsModule
|
||||
FormsModule,
|
||||
MultiSelectModule
|
||||
]
|
||||
})
|
||||
export class MultiEnumEditFieldModule {
|
||||
|
|
|
@ -28,27 +28,23 @@
|
|||
<div class="d-flex">
|
||||
<ng-container *ngIf="initModule">
|
||||
<div class="flex-grow-1">
|
||||
<tag-input #tag
|
||||
(keyup.enter)="selectFirstElement()"
|
||||
(onAdd)="onAdd($event)"
|
||||
(onBlur)="resetStatus()"
|
||||
(onRemove)="onRemove()"
|
||||
[(ngModel)]="selectedValues"
|
||||
[class]="getInvalidClass()"
|
||||
[clearOnBlur]="true"
|
||||
[displayBy]="getRelateFieldName()"
|
||||
[inputClass]="getInvalidClass()"
|
||||
[onTextChangeDebounce]="500"
|
||||
[onlyFromAutocomplete]="true"
|
||||
[placeholder]="getPlaceholderLabel()"
|
||||
[secondaryPlaceholder]="getPlaceholderLabel()"
|
||||
maxItems="1">
|
||||
<tag-input-dropdown [autocompleteObservable]="search"
|
||||
[displayBy]="getRelateFieldName()"
|
||||
[keepOpen]="false"
|
||||
[showDropdownIfEmpty]="true">
|
||||
</tag-input-dropdown>
|
||||
</tag-input>
|
||||
<p-multiSelect
|
||||
#tag
|
||||
[options]="options"
|
||||
[(ngModel)]="selectedValues"
|
||||
[optionLabel]="getRelateFieldName()"
|
||||
(onChange)="onAdd($event.value[0])"
|
||||
(onBlur)="resetStatus()"
|
||||
(onRemove)="onRemove()"
|
||||
(onFilter)="onFilter($event)"
|
||||
[virtualScroll]="true"
|
||||
[virtualScrollItemSize]="40"
|
||||
[placeholder]="placeholderLabel"
|
||||
[emptyFilterMessage]="emptyFilterLabel"
|
||||
[selectionLimit]="1"
|
||||
[styleClass]="getInvalidClass()"
|
||||
>
|
||||
</p-multiSelect>
|
||||
</div>
|
||||
<div class="relate-btn">
|
||||
<scrm-button [config]="selectButton">
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
*/
|
||||
|
||||
import {Component, ViewChild} from '@angular/core';
|
||||
import {TagInputComponent} from 'ngx-chips';
|
||||
import {ButtonInterface, Field, Record} from 'common';
|
||||
import {NgbModal} from '@ng-bootstrap/ng-bootstrap';
|
||||
import {ModuleNameMapper} from '../../../../services/navigation/module-name-mapper/module-name-mapper.service';
|
||||
|
@ -35,9 +34,10 @@ import {BaseRelateComponent} from '../../../base/base-relate.component';
|
|||
import {LanguageStore} from '../../../../store/language/language.store';
|
||||
import {RelateService} from '../../../../services/record/relate/relate.service';
|
||||
import {RecordListModalResult} from '../../../../containers/record-list-modal/components/record-list-modal/record-list-modal.model';
|
||||
import {TagModel} from 'ngx-chips/core/tag-model';
|
||||
import {FieldLogicManager} from '../../../field-logic/field-logic.manager';
|
||||
import {FieldLogicDisplayManager} from '../../../field-logic-display/field-logic-display.manager';
|
||||
import {map, take} from "rxjs/operators";
|
||||
import {MultiSelect} from "primeng/multiselect";
|
||||
|
||||
@Component({
|
||||
selector: 'scrm-relate-edit',
|
||||
|
@ -46,10 +46,13 @@ import {FieldLogicDisplayManager} from '../../../field-logic-display/field-logic
|
|||
providers: [RelateService]
|
||||
})
|
||||
export class RelateEditFieldComponent extends BaseRelateComponent {
|
||||
@ViewChild('tag') tag: TagInputComponent;
|
||||
@ViewChild('tag') tag: MultiSelect;
|
||||
selectButton: ButtonInterface;
|
||||
idField: Field;
|
||||
|
||||
placeholderLabel: string = '';
|
||||
emptyFilterLabel: string = '';
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
|
@ -113,9 +116,8 @@ export class RelateEditFieldComponent extends BaseRelateComponent {
|
|||
this.field.formControl.setValue('');
|
||||
return;
|
||||
}
|
||||
|
||||
this.selectedValues = [];
|
||||
this.selectedValues.push(this.field.valueObject);
|
||||
this.selectedValues = [this.field.valueObject];
|
||||
this.options = [this.field.valueObject];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -124,8 +126,7 @@ export class RelateEditFieldComponent extends BaseRelateComponent {
|
|||
* @param {object} item added
|
||||
*/
|
||||
onAdd(item): void {
|
||||
|
||||
if (item) {
|
||||
if(item) {
|
||||
const relateName = this.getRelateFieldName();
|
||||
this.setValue(item.id, item[relateName]);
|
||||
return;
|
||||
|
@ -143,10 +144,23 @@ export class RelateEditFieldComponent extends BaseRelateComponent {
|
|||
onRemove(): void {
|
||||
this.setValue('', '');
|
||||
this.selectedValues = [];
|
||||
this.options = [];
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
this.tag.focus(true, true);
|
||||
}, 200);
|
||||
onFilter($event): void {
|
||||
this.onRemove();
|
||||
const relateName = this.getRelateFieldName();
|
||||
let term = $event.filter;
|
||||
this.search(term).pipe(
|
||||
take(1),
|
||||
map(data => data.filter(item => item[relateName] !== '')),
|
||||
map(filteredData => filteredData.map(item => ({
|
||||
id: item.id,
|
||||
[relateName]: item[relateName]
|
||||
})))
|
||||
).subscribe(filteredOptions => {
|
||||
this.options = filteredOptions;
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -167,6 +181,13 @@ export class RelateEditFieldComponent extends BaseRelateComponent {
|
|||
this.idField.formControl.setValue(id);
|
||||
this.idField.formControl.markAsDirty();
|
||||
}
|
||||
|
||||
if(relateValue) {
|
||||
const relateName = this.getRelateFieldName();
|
||||
this.selectedValues = [{ id: id, [relateName]: relateValue }];
|
||||
}
|
||||
|
||||
this.options = this.selectedValues;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -223,14 +244,8 @@ export class RelateEditFieldComponent extends BaseRelateComponent {
|
|||
this.onAdd(record.attributes);
|
||||
}
|
||||
|
||||
public selectFirstElement(): void {
|
||||
const filteredElements: TagModel = this.tag.dropdown.items;
|
||||
if (filteredElements.length !== 0) {
|
||||
const firstElement = filteredElements[0];
|
||||
this.selectedValues.push(firstElement);
|
||||
this.onAdd(firstElement);
|
||||
this.tag.dropdown.hide();
|
||||
}
|
||||
public getTranslatedLabels(): void {
|
||||
this.placeholderLabel = this.languages.getAppString('LBL_SELECT_ITEM') || '';
|
||||
this.emptyFilterLabel = this.languages.getAppString('ERR_SEARCH_NO_RESULTS') || '';
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -27,22 +27,20 @@
|
|||
import {NgModule} from '@angular/core';
|
||||
import {CommonModule} from '@angular/common';
|
||||
import {RelateEditFieldComponent} from './relate.component';
|
||||
import {TagInputModule} from 'ngx-chips';
|
||||
import {FormsModule} from '@angular/forms';
|
||||
import {InlineLoadingSpinnerModule} from '../../../../components/inline-loading-spinner/inline-loading-spinner.module';
|
||||
import {ButtonModule} from '../../../../components/button/button.module';
|
||||
import {LabelModule} from '../../../../components/label/label.module';
|
||||
import {MultiSelectModule} from "primeng/multiselect";
|
||||
|
||||
@NgModule({
|
||||
declarations: [RelateEditFieldComponent],
|
||||
exports: [RelateEditFieldComponent],
|
||||
imports: [
|
||||
CommonModule,
|
||||
TagInputModule,
|
||||
LabelModule,
|
||||
FormsModule,
|
||||
InlineLoadingSpinnerModule,
|
||||
ButtonModule
|
||||
ButtonModule,
|
||||
MultiSelectModule
|
||||
]
|
||||
})
|
||||
export class RelateEditFieldModule {
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
/**
|
||||
* SuiteCRM is a customer relationship management program developed by SalesAgility Ltd.
|
||||
* Copyright (C) 2023 SalesAgility Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Affero General Public License version 3 as published by the
|
||||
* Free Software Foundation with the addition of the following permission added
|
||||
* to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
|
||||
* IN WHICH THE COPYRIGHT IS OWNED BY SALESAGILITY, SALESAGILITY DISCLAIMS THE
|
||||
* WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License
|
||||
* version 3, these Appropriate Legal Notices must retain the display of the
|
||||
* "Supercharged by SuiteCRM" logo. If the display of the logos is not reasonably
|
||||
* feasible for technical reasons, the Appropriate Legal Notices must display
|
||||
* the words "Supercharged by SuiteCRM".
|
||||
*/
|
||||
|
||||
/* --------- MESSAGE SECTION ---------- */
|
||||
|
||||
.p-multiselect {
|
||||
width: 100%;
|
||||
height: calc(1.5em + 0.5rem + 1px);
|
||||
|
||||
.p-multiselect-label {
|
||||
font-size: 0.85rem;
|
||||
padding: 0.35rem 0.48rem;
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
.p-multiselect-panel {
|
||||
.p-inputtext {
|
||||
padding: 0.3rem 0.6rem;
|
||||
}
|
||||
.p-multiselect-close {
|
||||
padding: 0.6em;
|
||||
}
|
||||
ul.p-multiselect-items {
|
||||
padding-inline-start: 0em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -80,6 +80,7 @@
|
|||
@import 'components/action-group-menu';
|
||||
@import 'components/popover';
|
||||
@import 'components/popover-mobile';
|
||||
@import 'components/multiselect';
|
||||
|
||||
@import 'layout/panel';
|
||||
@import 'layout/app';
|
||||
|
|
|
@ -68,6 +68,7 @@
|
|||
"ngx-chips": "^3.0.0",
|
||||
"nyc": "~15.1.0",
|
||||
"object-hash": "^3.0.0",
|
||||
"primeng": "^16.9.1",
|
||||
"rxjs": "^7.8.1",
|
||||
"tinymce": "^6.4.2",
|
||||
"tslib": "^2.5.2",
|
||||
|
|
|
@ -7911,6 +7911,13 @@ pretty-format@^29.7.0:
|
|||
ansi-styles "^5.0.0"
|
||||
react-is "^18.0.0"
|
||||
|
||||
primeng@^16.9.1:
|
||||
version "16.9.1"
|
||||
resolved "https://registry.yarnpkg.com/primeng/-/primeng-16.9.1.tgz#50ee3ed304633c1c5a8ea155f6c0c8be9de7b85c"
|
||||
integrity sha512-dCkvKoV62xDEyeGaEm8B0qncdKWNz4mDU/Camnr27AafaDNGV0lCA29imgJvZPEmJTmC2wDhtedg7Syfwz4UqA==
|
||||
dependencies:
|
||||
tslib "^2.3.0"
|
||||
|
||||
proc-log@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/proc-log/-/proc-log-3.0.0.tgz#fb05ef83ccd64fd7b20bbe9c8c1070fc08338dd8"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue