File

packages/data/src/lib/resource-select/resource-select.component.ts

Description

Shows resources of a selection and is able to pick new ones from a crud list

Extends

SelectComponent

Implements

OnChanges OnInit

Metadata

encapsulation ViewEncapsulation.None
providers { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => ResourceSelectComponent), multi: true, }
selector ec-resource-select
templateUrl ./resource-select.component.html

Index

Properties
Methods
Inputs
Outputs

Constructor

constructor(resourceConfig: ResourceConfig, auth: AuthService, elementRef: ElementRef, symbol: SymbolService, cdr: ChangeDetectorRef)
Parameters :
Name Type Optional
resourceConfig ResourceConfig No
auth AuthService No
elementRef ElementRef No
symbol SymbolService No
cdr ChangeDetectorRef No

Inputs

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

Outputs

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

Methods

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 :
Name Optional
item No
e No
Returns : any
defaultPlaceholder
defaultPlaceholder()
Returns : any
editItem
editItem(item: Item, e)

Is called when a selected item has been clicked.

Parameters :
Name Type Optional
item Item<Resource> No
e No
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 :
Name Type Optional
form Form<EntryResource> No
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 :
Name Type Optional
method string No
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 :
Name Optional
e No
Returns : void
togglePop
togglePop(e?, noFocus)
Parameters :
Name Optional Default value
e Yes
noFocus No false
Returns : void
useConfig
useConfig(config: CrudConfig)

Calls super.useConfig and then creates special dropdownConfig with just entryTitle as field

Parameters :
Name Type Optional Default value
config CrudConfig<Resource> No {}
Returns : void
useMethods
useMethods(methods)
Parameters :
Name Optional
methods No
Returns : void
activate
activate(e)
Inherited from SelectComponent
Parameters :
Name Optional
e No
Returns : void
addItem
addItem(item: Item)
Inherited from SelectComponent

Adds the given ite, emits add output if observed

Parameters :
Name Type Optional
item Item<any> No
Returns : void
cancelDrag
cancelDrag(item, e, target)
Inherited from SelectComponent

is called when the drag stops in any kind of way.

Parameters :
Name Optional Default value
item No
e No
target No e.target
Returns : void
canRemove
canRemove()
Inherited from SelectComponent
Returns : boolean
Public clickItem
clickItem(item, e?)
Inherited from SelectComponent

Is called when a selected item is clicked

Parameters :
Name Optional
item No
e Yes
Returns : void
filterDropdownList
filterDropdownList(listComponent: ListComponent, query)
Inherited from SelectComponent
Parameters :
Name Type Optional
listComponent ListComponent<any> No
query No
Returns : void
focus
focus(e)
Inherited from SelectComponent
Parameters :
Name Optional
e No
Returns : void
focusSearchbar
focusSearchbar()
Inherited from SelectComponent
Returns : void
getArray
getArray(value)
Inherited from SelectComponent
Parameters :
Name Optional
value No
Returns : any
getParentTree
getParentTree(el, tree: [])
Inherited from SelectComponent
Parameters :
Name Type Optional Default value
el No
tree [] No []
Returns : any
handleKey
handleKey(e, list)
Inherited from SelectComponent
Parameters :
Name Optional
e No
list No
Returns : void
hasSoloSelection
hasSoloSelection()
Inherited from SelectComponent
Returns : boolean
initSelection
initSelection()
Inherited from SelectComponent

creates the collection from the config

Returns : void
Public listItemClicked
listItemClicked(item, list?)
Inherited from SelectComponent

Select handler. Toggles selection.

Parameters :
Name Optional
item No
list Yes
Returns : void
ngOnChanges
ngOnChanges()
Inherited from SelectComponent
Returns : void
ngOnInit
ngOnInit()
Inherited from SelectComponent
Returns : void
onChange
onChange()
Inherited from SelectComponent

Fires on selection change. Hides dropdown if solo

Returns : void
onDragStart
onDragStart(item, e, target)
Inherited from SelectComponent

is called when an element is dragged by the user. hides element in selection

Parameters :
Name Optional Default value
item No
e No
target No e.target
Returns : void
onDrop
onDrop(e)
Inherited from SelectComponent

called when the element is dropped. moves item in selection.

Parameters :
Name Optional
e No
Returns : void
preventDefault
preventDefault(e)
Inherited from SelectComponent
Parameters :
Name Optional
e No
Returns : void
registerOnChange
registerOnChange(fn)
Inherited from SelectComponent

registers change method. (handled by angular)

Parameters :
Name Optional
fn No
Returns : void
registerOnTouched
registerOnTouched()
Inherited from SelectComponent
Returns : void
removeItem
removeItem(item: Item, e?)
Inherited from SelectComponent

Removes the given item from selection

Parameters :
Name Type Optional
item Item<any> No
e Yes
Returns : void
setDisabledState
setDisabledState(isDisabled)
Inherited from SelectComponent
Parameters :
Name Optional
isDisabled No
Returns : void
use
use(value, event)
Inherited from SelectComponent

Uses the given value as selection items

Parameters :
Name Optional Default value
value No
event No true
Returns : void
useConfig
useConfig(config: ListConfig)
Inherited from SelectComponent

Initializes either with values, collection or list. Creates Selection with config.

Parameters :
Name Type Optional Default value
config ListConfig<T> No {}
Returns : void
writeValue
writeValue(value: any)
Inherited from SelectComponent

Called when the model changes

Parameters :
Name Type Optional
value any No
Returns : void

Properties

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

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">&times;</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>
Legend
Html element
Component
Html element with directive

result-matching ""

    No results matching ""