packages/data/src/lib/resource-select/resource-select.component.ts
Shows resources of a selection and is able to pick new ones from a crud list
encapsulation | ViewEncapsulation.None |
providers |
{
provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => ResourceSelectComponent), multi: true,
}
|
selector | ec-resource-select |
templateUrl | ./resource-select.component.html |
Properties |
|
Methods |
|
Inputs |
Outputs |
constructor(resourceConfig: ResourceConfig, auth: AuthService, elementRef: ElementRef, symbol: SymbolService, cdr: ChangeDetectorRef)
|
||||||||||||||||||
Parameters :
|
api | |
Type : Core
|
|
The api to use |
config | |
Type : CrudConfig<Resource>
|
|
The config that should be merged into the generated config |
focusEvent | |
Type : EventEmitter<boolean>
|
|
Default value : new EventEmitter()
|
|
The event that focuses the input |
formControl | |
Type : FormControl
|
|
The formControl that is used. |
relation | |
Type : string
|
|
The relation of the resource. |
solo | |
Type : boolean
|
|
Wether or not the selection should be solo |
value | |
Type : Array<Resource>
|
|
The value that should be prefilled |
config | |
Type : ListConfig<T>
|
|
Inherited from
SelectComponent
|
|
Defined in
SelectComponent:48
|
|
Configuration Object for List |
disabled | |
Type : ListConfig<T>
|
|
Inherited from
SelectComponent
|
|
Defined in
SelectComponent:50
|
|
If true, the input will be disabled |
focusEvent | |
Type : EventEmitter<boolean>
|
|
Default value : new EventEmitter()
|
|
Inherited from
SelectComponent
|
|
Defined in
SelectComponent:76
|
|
Event emitter to focus input |
formControl | |
Type : FormControl
|
|
Inherited from
SelectComponent
|
|
Defined in
SelectComponent:88
|
|
The formControl that is used. |
list | |
Type : List<T>
|
|
Inherited from
SelectComponent
|
|
Defined in
SelectComponent:70
|
|
The Instance of the List |
placeholder | |
Type : string
|
|
Inherited from
SelectComponent
|
|
Defined in
SelectComponent:56
|
|
Input placeholder |
selection | |
Type : Selection<T>
|
|
Inherited from
SelectComponent
|
|
Defined in
SelectComponent:54
|
|
The used selection |
solo | |
Type : boolean
|
|
Inherited from
SelectComponent
|
|
Defined in
SelectComponent:74
|
|
Wether or not the selection should be solo |
value | |
Type : Array<T> | T
|
|
Inherited from
SelectComponent
|
|
Defined in
SelectComponent:52
|
|
The visible items |
values | |
Type : Array<T>
|
|
Inherited from
SelectComponent
|
|
Defined in
SelectComponent:72
|
|
Available Items |
add | |
Type : EventEmitter<Item<T>>
|
|
Inherited from
SelectComponent
|
|
Defined in
SelectComponent:64
|
|
Emits when an item is being added |
changed | |
Type : EventEmitter<Selection<T>>
|
|
Inherited from
SelectComponent
|
|
Defined in
SelectComponent:58
|
|
Event emitter on item selection |
enter | |
Type : EventEmitter<SelectComponent<T>>
|
|
Inherited from
SelectComponent
|
|
Defined in
SelectComponent:66
|
|
Emits the query when enter is pressed |
enterPressed | |
Type : Subject<string>
|
|
Inherited from
SelectComponent
|
|
Defined in
SelectComponent:68
|
|
Subject that is nexted when enter is pressed |
itemClick | |
Type : EventEmitter<Item<T>>
|
|
Inherited from
SelectComponent
|
|
Defined in
SelectComponent:60
|
|
Event emitter on selected item click |
remove | |
Type : EventEmitter<Item<T>>
|
|
Inherited from
SelectComponent
|
|
Defined in
SelectComponent:62
|
|
Emits when an item is being removed |
clickItem | ||||||
clickItem(item, e)
|
||||||
Is called when a selected item is clicked. Either outputs itemClick (if subscribed) or opens the edit pop if puttable.
Parameters :
Returns :
any
|
defaultPlaceholder |
defaultPlaceholder()
|
Returns :
any
|
editItem | |||||||||
editItem(item: Item
|
|||||||||
Is called when a selected item has been clicked.
Parameters :
Returns :
void
|
focusSearchbar |
focusSearchbar()
|
Returns :
void
|
formSubmitted | ||||||
formSubmitted(form: Form
|
||||||
Is called when the nested resource-form has been saved. Selects the fresh resource and clears the form
Parameters :
Returns :
void
|
Public hasMethod | ||||||
hasMethod(method: string)
|
||||||
Returns true if the given method is part of the methods array (or if there is no methods array)
Parameters :
Returns :
boolean
|
init |
init()
|
Inits the select with api, relation and config setup
Returns :
void
|
ngOnChanges |
ngOnChanges()
|
Returns :
void
|
ngOnInit |
ngOnInit()
|
Returns :
void
|
onChange |
onChange()
|
Returns :
void
|
pasteValue | ||||
pasteValue(e)
|
||||
Parameters :
Returns :
void
|
togglePop | |||||||||
togglePop(e?, noFocus)
|
|||||||||
Parameters :
Returns :
void
|
useConfig | ||||||||
useConfig(config: CrudConfig
|
||||||||
Calls super.useConfig and then creates special dropdownConfig with just entryTitle as field
Parameters :
Returns :
void
|
useMethods | ||||
useMethods(methods)
|
||||
Parameters :
Returns :
void
|
activate | ||||
activate(e)
|
||||
Inherited from
SelectComponent
|
||||
Defined in
SelectComponent:283
|
||||
Parameters :
Returns :
void
|
addItem | ||||||
addItem(item: Item
|
||||||
Inherited from
SelectComponent
|
||||||
Defined in
SelectComponent:166
|
||||||
Adds the given ite, emits add output if observed
Parameters :
Returns :
void
|
cancelDrag | ||||||||||||
cancelDrag(item, e, target)
|
||||||||||||
Inherited from
SelectComponent
|
||||||||||||
Defined in
SelectComponent:276
|
||||||||||||
is called when the drag stops in any kind of way.
Parameters :
Returns :
void
|
canRemove |
canRemove()
|
Inherited from
SelectComponent
|
Defined in
SelectComponent:298
|
Returns :
boolean
|
Public clickItem | ||||||
clickItem(item, e?)
|
||||||
Inherited from
SelectComponent
|
||||||
Defined in
SelectComponent:203
|
||||||
Is called when a selected item is clicked
Parameters :
Returns :
void
|
filterDropdownList | |||||||||
filterDropdownList(listComponent: ListComponent
|
|||||||||
Inherited from
SelectComponent
|
|||||||||
Defined in
SelectComponent:360
|
|||||||||
Parameters :
Returns :
void
|
focus | ||||
focus(e)
|
||||
Inherited from
SelectComponent
|
||||
Defined in
SelectComponent:219
|
||||
Parameters :
Returns :
void
|
focusSearchbar |
focusSearchbar()
|
Inherited from
SelectComponent
|
Defined in
SelectComponent:229
|
Returns :
void
|
getArray | ||||
getArray(value)
|
||||
Inherited from
SelectComponent
|
||||
Defined in
SelectComponent:175
|
||||
Parameters :
Returns :
any
|
getParentTree | ||||||||||||
getParentTree(el, tree: [])
|
||||||||||||
Inherited from
SelectComponent
|
||||||||||||
Defined in
SelectComponent:103
|
||||||||||||
Parameters :
Returns :
any
|
handleKey | ||||||
handleKey(e, list)
|
||||||
Inherited from
SelectComponent
|
||||||
Defined in
SelectComponent:302
|
||||||
Parameters :
Returns :
void
|
hasSoloSelection |
hasSoloSelection()
|
Inherited from
SelectComponent
|
Defined in
SelectComponent:225
|
Returns :
boolean
|
initSelection |
initSelection()
|
Inherited from
SelectComponent
|
Defined in
SelectComponent:119
|
creates the collection from the config
Returns :
void
|
Public listItemClicked | ||||||
listItemClicked(item, list?)
|
||||||
Inherited from
SelectComponent
|
||||||
Defined in
SelectComponent:210
|
||||||
Select handler. Toggles selection.
Parameters :
Returns :
void
|
ngOnChanges |
ngOnChanges()
|
Inherited from
SelectComponent
|
Defined in
SelectComponent:114
|
Returns :
void
|
ngOnInit |
ngOnInit()
|
Inherited from
SelectComponent
|
Defined in
SelectComponent:110
|
Returns :
void
|
onChange |
onChange()
|
Inherited from
SelectComponent
|
Defined in
SelectComponent:236
|
Fires on selection change. Hides dropdown if solo
Returns :
void
|
onDragStart | ||||||||||||
onDragStart(item, e, target)
|
||||||||||||
Inherited from
SelectComponent
|
||||||||||||
Defined in
SelectComponent:257
|
||||||||||||
is called when an element is dragged by the user. hides element in selection
Parameters :
Returns :
void
|
onDrop | ||||
onDrop(e)
|
||||
Inherited from
SelectComponent
|
||||
Defined in
SelectComponent:264
|
||||
called when the element is dropped. moves item in selection.
Parameters :
Returns :
void
|
preventDefault | ||||
preventDefault(e)
|
||||
Inherited from
SelectComponent
|
||||
Defined in
SelectComponent:292
|
||||
Parameters :
Returns :
void
|
registerOnChange | ||||
registerOnChange(fn)
|
||||
Inherited from
SelectComponent
|
||||
Defined in
SelectComponent:250
|
||||
registers change method. (handled by angular)
Parameters :
Returns :
void
|
registerOnTouched |
registerOnTouched()
|
Inherited from
SelectComponent
|
Defined in
SelectComponent:254
|
Returns :
void
|
removeItem | |||||||||
removeItem(item: Item
|
|||||||||
Inherited from
SelectComponent
|
|||||||||
Defined in
SelectComponent:153
|
|||||||||
Removes the given item from selection
Parameters :
Returns :
void
|
setDisabledState | ||||
setDisabledState(isDisabled)
|
||||
Inherited from
SelectComponent
|
||||
Defined in
SelectComponent:371
|
||||
Parameters :
Returns :
void
|
use | |||||||||
use(value, event)
|
|||||||||
Inherited from
SelectComponent
|
|||||||||
Defined in
SelectComponent:180
|
|||||||||
Uses the given value as selection items
Parameters :
Returns :
void
|
useConfig | ||||||||
useConfig(config: ListConfig
|
||||||||
Inherited from
SelectComponent
|
||||||||
Defined in
SelectComponent:196
|
||||||||
Initializes either with values, collection or list. Creates Selection with config.
Parameters :
Returns :
void
|
writeValue | ||||||
writeValue(value: any)
|
||||||
Inherited from
SelectComponent
|
||||||
Defined in
SelectComponent:148
|
||||||
Called when the model changes
Parameters :
Returns :
void
|
Public cdr |
Type : ChangeDetectorRef
|
Public config |
Type : CrudConfig<Resource>
|
The config that is being generated. |
Protected control |
Type : FormControl
|
The form control that is used |
dropdown |
Type : PopComponent
|
Decorators :
@ViewChild('dropdown', {static: true})
|
The crud pop with the list to select from |
dropdownConfig |
Type : CrudConfig<Resource>
|
The config of the dropdown pop |
dropdownList |
Type : ResourceListComponent
|
Decorators :
@ViewChild('dropdownList')
|
The nested resource list in the dropdown |
Public elementRef |
Type : ElementRef
|
Protected group |
Type : FormGroup
|
The form group that is used |
Protected item |
Type : Item<any>
|
The item that is targeted by the input |
resourceListPop |
Type : ResourceListPopComponent
|
Decorators :
@ViewChild(ResourceListPopComponent, {static: true})
|
The nested resource list pop |
resourcePop |
Type : ResourcePopComponent
|
Decorators :
@ViewChild(ResourcePopComponent)
|
The nested resource pop for editing and creating |
Public symbol |
Type : SymbolService
|
Public cdr |
Type : ChangeDetectorRef
|
Inherited from
SelectComponent
|
Defined in
SelectComponent:90
|
dragged |
Type : Item<T>
|
Inherited from
SelectComponent
|
Defined in
SelectComponent:46
|
the current dragged element |
dropdown |
Type : PopComponent
|
Decorators :
@ViewChild('dropdown', {static: true})
|
Inherited from
SelectComponent
|
Defined in
SelectComponent:78
|
The selection dropdown |
dropdownList |
Type : ListComponent<any>
|
Decorators :
@ViewChild(ListComponent, {static: true})
|
Inherited from
SelectComponent
|
Defined in
SelectComponent:82
|
The list in the dropdown |
dropdownLoader |
Type : LoaderComponent
|
Decorators :
@ViewChild('dropdownLoader', {static: true})
|
Inherited from
SelectComponent
|
Defined in
SelectComponent:80
|
The loader inside the dropdown |
Public elementRef |
Type : ElementRef
|
Inherited from
SelectComponent
|
Defined in
SelectComponent:90
|
propagateChange |
Default value : () => {...}
|
Inherited from
SelectComponent
|
Defined in
SelectComponent:248
|
Propagates formControl/ngModel changes |
searchbar |
Type : SearchbarComponent
|
Decorators :
@ViewChild(SearchbarComponent)
|
Inherited from
SelectComponent
|
Defined in
SelectComponent:84
|
The nested searchbar |
toggleItem |
Type : Subject<Item<T>>
|
Default value : new Subject()
|
Inherited from
SelectComponent
|
Defined in
SelectComponent:86
|
Subject that is nexted when an item is being selected (clicked or entered on) |
import {
ChangeDetectorRef,
Component,
ElementRef,
EventEmitter, forwardRef,
Input,
OnChanges,
OnInit,
ViewChild,
ViewEncapsulation
} from '@angular/core';
import { FormControl, FormGroup, NG_VALUE_ACCESSOR } from '@angular/forms';
import { Form, Item } from '@ec.components/core';
import { PopComponent, SelectComponent, SymbolService } from '@ec.components/ui';
import Core from 'ec.sdk/lib/Core';
import EntryResource from 'ec.sdk/lib/resources/publicAPI/EntryResource';
import Resource from 'ec.sdk/lib/resources/Resource';
import { AuthService } from '../auth/auth.service';
import { CrudConfig } from '../crud/crud-config.interface';
import { ResourceConfig } from '../resource-config/resource-config.service';
import { ResourceListPopComponent } from '../resource-list-pop/resource-list-pop.component';
import { ResourceListComponent } from '../resource-list/resource-list.component';
import { ResourcePopComponent } from '../resource-pop/resource-pop.component';
/** Shows resources of a selection and is able to pick new ones from a crud list
*/
@Component({
selector: 'ec-resource-select',
templateUrl: './resource-select.component.html',
encapsulation: ViewEncapsulation.None,
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => ResourceSelectComponent),
multi: true,
},
],
})
export class ResourceSelectComponent extends SelectComponent<Resource> implements OnChanges, OnInit {
/** The item that is targeted by the input */
protected item: Item<any>;
/** The form group that is used */
protected group: FormGroup;
/** The form control that is used */
protected control: FormControl;
/** The formControl that is used. */
@Input() formControl: FormControl;
/** The value that should be prefilled */
@Input() value: Array<Resource>;
/** The relation of the resource. */
@Input() relation: string;
/** The api to use */
@Input() api: Core;
/** The config that is being generated. */
public config: CrudConfig<Resource>;
/** Wether or not the selection should be solo */
@Input() solo: boolean;
/** The config that should be merged into the generated config */
// tslint:disable-next-line:no-input-rename
@Input('config') crudConfig: CrudConfig<Resource>;
/** The crud pop with the list to select from */
@ViewChild('dropdown', { static: true }) dropdown: PopComponent;
/** The nested resource list in the dropdown */
@ViewChild('dropdownList') dropdownList: ResourceListComponent;
/** The nested resource pop for editing and creating */
@ViewChild(ResourcePopComponent) resourcePop: ResourcePopComponent;
/** The nested resource list pop */
@ViewChild(ResourceListPopComponent, { static: true }) resourceListPop: ResourceListPopComponent;
/** The config of the dropdown pop */
dropdownConfig: CrudConfig<Resource>;
/** The event that focuses the input */
@Input() focusEvent: EventEmitter<boolean> = new EventEmitter();
constructor(
protected resourceConfig: ResourceConfig,
protected auth: AuthService,
public elementRef: ElementRef,
public symbol: SymbolService,
public cdr: ChangeDetectorRef,
) {
super(elementRef, cdr);
this.focusEvent.subscribe((focus) => {
if (focus) {
this.togglePop(null, true);
}
});
}
ngOnInit() {
this.init();
}
ngOnChanges() {
this.init();
}
togglePop(e?, noFocus = false) {
if (this.disabled) {
if (!this.selection.isEmpty()) {
this.editItem(this.selection.display[0], e);
}
return;
}
if (this.dropdown && this.config && !this.config.disableSearchbar) {
this.dropdown.show(e);
} else if (this.resourceListPop && this.config && !this.config.disableListPop) {
this.resourceListPop.show(e);
} else if (this.resourcePop && !this.config.disableCreatePop) {
this.resourcePop.show();
}
if (!noFocus) {
this.focusSearchbar();
}
}
defaultPlaceholder() {
if (this.config && this.config.disableSearchbar && this.config.disableListPop) {
return this.symbol.resolve('resource.select.placeholder.new');
}
return this.symbol.resolve('resource.select.placeholder.select');
}
/** Calls super.useConfig and then creates special dropdownConfig with just entryTitle as field */
useConfig(config: CrudConfig<Resource> = {}) {
super.useConfig(config);
this.dropdownConfig = Object.assign({}, this.config, {
disableHeader: true,
defaultFilter: false,
fields: this.config.dropdownFields || {
[this.config.label]: Object.assign({}, this.config.fields ? this.config.fields[this.config.label] || {} : {}),
},
});
if (config.methods) {
this.useMethods(config.methods);
} else {
this.auth
.getAllowedResourceMethods(this.relation) // init permissions
.then((methods) => this.useMethods(methods));
}
this.selection.update$.subscribe((change) => {
if (this.solo && !this.selection.isEmpty()) {
// update permissions for selected item
this.auth
.getAllowedResourceMethods(this.relation, { [this.config.identifier]: this.selection.getValue() })
.then((methods) => this.useMethods(methods));
}
});
}
/** Is called when a selected item is clicked. Either outputs itemClick (if subscribed) or opens the edit pop if puttable. */
clickItem(item, e) {
if (!this.solo && this.hasMethod('put')) {
this.editItem(item, e);
}
if (this.itemClick.observers.length) {
e.preventDefault();
e.stopPropagation();
e.stopImmediatePropagation();
return this.itemClick.emit(item);
}
}
useMethods(methods) {
this.config.methods = methods;
this.cdr.markForCheck();
}
/** Returns true if the given method is part of the methods array (or if there is no methods array) */
public hasMethod(method: string) {
return this.config && this.config.methods && this.config.methods.indexOf(method) !== -1;
}
/** Inits the select with api, relation and config setup */
init() {
if (!this.api || !this.relation) {
return;
}
if (!this.formControl) {
this.formControl = new FormControl(this.value || []);
}
if (this.config) {
this.useConfig(this.config);
return;
}
this.config = <CrudConfig<Resource>>Object.assign(
this.resourceConfig.get(this.relation) /* , { size: 5 } */,
this.crudConfig,
{
solo: this.solo,
selectMode: false,
disableSelectSwitch: true,
} as CrudConfig<Resource>,
);
this.useConfig(this.config);
}
/** Is called when the nested resource-form has been saved. Selects the fresh resource and clears the form */
formSubmitted(form: Form<EntryResource>) {
if (!this.selection.has(form)) {
this.toggleItem.next(form);
} else {
// already in selection => update body
const index = this.selection.index(form);
this.selection.items[index].body = form.getBody();
}
}
pasteValue(e) {
const value = e.clipboardData.getData('text');
if (this.config.identifierPattern && value.match(this.config.identifierPattern)) {
this.preventDefault(e);
this.api
.resource(this.relation, value)
.then((resource) => this.addItem(new Item(resource, this.config)))
.catch((error) => this.searchbar.filterList(value));
}
}
/** Is called when a selected item has been clicked. */
editItem(item: Item<Resource>, e) {
this.auth.getAllowedResourceMethods(this.relation, { [this.config.identifier]: item.id() }).then((methods) => {
if (methods.indexOf('put') === -1) {
return;
}
this.resourcePop.edit(item.getBody(), { methods });
});
}
onChange() {
super.onChange();
if (this.hasSoloSelection() && this.resourceListPop) {
this.resourceListPop.hide();
return;
}
}
focusSearchbar() {
if ((!this.resourceListPop || !this.resourceListPop.active) && this.focusEvent) {
this.focusEvent.emit(true);
}
}
}
<div class="ec-resource-select">
<div class="ec-select" [class.ec-select_solo]="solo" [class.is-empty]="selection?.isEmpty()"
(click)="togglePop($event)" [class.has-searchbar]="!config?.disableSearchbar">
<ul class="ec-select-selection">
<li *ngIf="config?.disableSearchbar&&selection.isEmpty()">
<span class="ec-select__placeholder">
{{placeholder||defaultPlaceholder()}}
</span>
</li>
<li *ngFor="let selected of selection?.items">
<span [class.ec-select-selected]="!solo" [class.ec-select-selected_solo]="solo"
(click)="clickItem(selected, $event)">
{{selected.display()}}
<a (click)="removeItem(selected,$event);" *ngIf="!config?.disableRemove&&!disabled">×</a>
</span>
</li>
<li *ngIf="!config?.disableSearchbar" class="ec-select__searchbar">
<ec-searchbar [disabled]="disabled" [focusEvent]="focusEvent" [autofocus]="false" [property]="config?.label||dropdownConfig?.label"
[placeholder]="placeholder||defaultPlaceholder()" (pasted)="pasteValue($event)"
(keypressed)="handleKey($event,dropdownList)" (focus)="focus($event)"
(queryChanged)="filterDropdownList(dropdownList,$event)"></ec-searchbar>
</li>
</ul>
<ec-pop class="ec-select-options" #dropdown [hideOnClickOutside]="true">
<ec-loader class="ec-loader loader is-local" #dropdownLoader></ec-loader>
<ec-resource-list (changed)="searchbar.updatedList($event)" #dropdownList *ngIf="dropdown.activated"
[relation]="relation" [api]="api" [config]="dropdownConfig" [selection]="selection" [loader]="dropdownLoader"
(columnClicked)="listItemClicked($event,dropdownList)"></ec-resource-list>
</ec-pop>
</div>
<ec-resource-list-pop (pasted)="pasteValue($event)" (columnClicked)="listItemClicked($event)" #resourceListPop
[api]="api" [relation]="relation" [config]="config" [selection]="selection"></ec-resource-list-pop>
<ec-resource-pop #resourcePop [api]="api" [relation]="relation" [config]="config" (submitted)="formSubmitted($event)"
(deleted)="removeItem($event)" *ngIf="config"></ec-resource-pop>
<nav class="ec-resource-select__controls">
<a (click)="editItem(selection?.items[0],$event)" class="btn btn_clear btn_square"
*ngIf="solo&&hasMethod('put')&&!selection?.isEmpty()">
<ec-icon name="edit"></ec-icon>
</a>
<a (click)="resourcePop.create()" class="btn btn_clear btn_square" *ngIf="!disabled&&!config?.disableCreatePop&&hasMethod('post')">
<ec-icon name="add"></ec-icon>
</a>
<a (click)="resourceListPop.show($event)" class="btn btn_clear btn_square" *ngIf="!config?.disableListPop&&hasMethod('get')&&!disabled">
<ec-icon name="search"></ec-icon>
</a>
</nav>
</div>