# @eqproject/eqp-lookup

> Dynamic lookup - Angular Material based

Latest version **21.0.1** (published 2026-05-07) · MIT license · 0 weekly downloads

## Install

```sh
npm install @eqproject/eqp-lookup
pnpm add @eqproject/eqp-lookup
yarn add @eqproject/eqp-lookup
bun add @eqproject/eqp-lookup
```

## Health

**Score 55/100 (C)** — status: active.

Positive: has types; esm support; no vulnerabilities.

Warnings: low downloads.

## Facts

| | |
|---|---|
| Version | 21.0.1 |
| Published | 2026-05-07 |
| First published | 2023-04-05 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | bundled |
| Module format | ESM + CommonJS |
| Dependencies | 1 |
| Unpacked size | 230.3 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| Author | EqProject |
| Maintainers | eqp, a.cipollone |

## Links

- npm: https://www.npmjs.com/package/@eqproject/eqp-lookup
- npm.io page: https://npm.io/package/@eqproject/eqp-lookup

## Dependencies (1)

- [tslib](https://npm.io/package/tslib.md) ^2.6.2

## Recent versions

- 21.0.1 (latest) — 2026-05-07
- 3.0.15 (v17-lts) — 2026-07-28
- 2.5.1 (v15-lts) — 2024-01-23
- 3.0.14 — 2026-06-18
- 3.0.13 — 2026-05-21
- 3.0.12 — 2026-05-14
- 21.0.0 — 2026-04-29
- 3.0.11 — 2026-02-25
- 3.0.10 — 2026-02-18
- 3.0.9 — 2026-02-13
- 3.0.8 — 2026-02-05
- 3.0.7 — 2026-01-21
- 3.0.6 — 2026-01-21
- 3.0.5 — 2025-11-18
- 3.0.4 — 2025-07-17
- … 11 more at https://npm.io/package/@eqproject/eqp-lookup/versions

## README

# Table of contents

- [Getting started](#getting-started)
- [ControlValueAccessor integration](#controlvalueaccessor-integration)
- [Add / Edit modal workflow](#add--edit-modal-workflow)
- [Server-side filtering](#server-side-filtering)
- [Public methods](#public-methods)
- [API](#api)
- [Models](#models)
- [Use Cases](#use-cases)
- [Credits](#credits)

## Required

- [x] Angular Material installed and imported
- [x] ng-select installed and imported (v. 21.x)

## Getting started

### Step 1: Install `eqp-lookup`:

#### NPM

```shell

npm install  --save  @eqproject/eqp-lookup

```

### Step 2: Import the EqpLookupModule:

```js
import { EqpLookupModule } from "@eqproject/eqp-lookup";

@NgModule({
  declarations: [AppComponent],
  imports: [EqpLookupModule],
  bootstrap: [AppComponent]
})
export class AppModule {}
```

### Step 3: Import ng-select styling:

#### Style.scss

```js

@import  "~@ng-select/ng-select/themes/material.theme.css";

```

## ControlValueAccessor integration

`EqpLookupComponent` implements `ControlValueAccessor`, which means it participates natively in Angular's reactive and template-driven form ecosystems without any adapter boilerplate.

The component supports **two binding modes** and they are mutually exclusive. Choose one per instance:

**FormGroup / FormControl mode** — pass `[formGroupInput]` and `[formControlNameInput]` together. The component writes the selected value directly into the form control and emits it via `(formControlChange)`.

```html
<eqp-lookup
  [entityType]="'City'"
  [initialItems]="cities"
  [formGroupInput]="myForm"
  [formControlNameInput]="'city'"
  (formControlChange)="onCityChange($event)">
</eqp-lookup>
```

**ngModel mode** — pass `[(ngModelInput)]` for two-way binding. Changes are emitted via `(ngModelInputChange)`.

```html
<eqp-lookup
  [entityType]="'City'"
  [initialItems]="cities"
  [(ngModelInput)]="selectedCity"
  (ngModelInputChange)="onCityChange($event)">
</eqp-lookup>
```

The component also responds correctly to `.disable()` / `.enable()` calls made on the parent `FormControl` or `FormGroup`, because `setDisabledState` is implemented in full.

When `[bindCompleteObject]="true"` (the default), the emitted value is the complete `LookupDTO` object. When `[bindCompleteObject]="false"`, only the value of `[bindKey]` (default `'ID'`) is emitted and written into the form control.


## Add / Edit modal workflow

The lookup supports inline creation and editing of entities through `[genericAddComponent]`. When configured, an add button (plus icon) is injected into the ng-select container automatically. If a selection is present and `[isEditable]="true"`, an edit button (pencil icon) is also injected.

### Setting up the host component

```html
<eqp-lookup
  [entityType]="'Question'"
  [fullUrlHttpCall]="fullUrlHttpCall"
  [genericAddComponent]="addConfig"
  [isEditable]="true"
  [formGroupInput]="myForm"
  [formControlNameInput]="'question'"
  (formControlChange)="onQuestionChange($event)"
  (lookupAddingCompleteParent)="onAddingComplete($event)">
</eqp-lookup>
```

```ts
import { DynamicLoaderDirectiveData } from '@eqproject/eqp-lookup';

addConfig: DynamicLoaderDirectiveData = {
  componentSelector: AddQuestionComponent,
  disableRedirectAfterSave: true,
  idLookupEntity: null
};
```

### Setting up the embedded component

The component loaded inside the modal (`AddQuestionComponent` in the example above) must inject `EqpLookupService` and emit `lookupAddingComplete` when the save operation finishes. Pass the ID of the saved entity as the payload; pass `null` to signal cancellation.

```ts
import { EqpLookupService } from '@eqproject/eqp-lookup';

@Component({ ... })
export class AddQuestionComponent {
  disableRedirectAfterSave: boolean = false; // required property

  constructor(private eqpLookupService: EqpLookupService) {}

  save() {
    // ... save logic ...
    this.eqpLookupService.lookupAddingComplete.emit(savedEntity.ID);
  }

  cancel() {
    this.eqpLookupService.lookupAddingComplete.emit(null);
  }
}
```

After `lookupAddingComplete` emits a non-null ID, the lookup automatically closes the modal, reloads its datasource via `reloadData(savedID)`, and pre-selects the newly saved item. If `[disableReloadOnLookupAddingCompleteParent]="true"` is set on the lookup, the automatic reload is skipped and only `(lookupAddingCompleteParent)` is emitted.

> **Note:** `disableRedirectAfterSave` is a convention-based property. If `disableRedirectAfterSave: true` is passed inside `DynamicLoaderDirectiveData`, the `DynamicLoaderDirective` will look for a public `disableRedirectAfterSave` property on the loaded component and set it to `true`. If the property does not exist on the component, a runtime error is thrown.


## Server-side filtering

When the lookup retrieves its data via `[fullUrlHttpCall]`, it posts a `LookupConfigDTO` payload to that endpoint. Two types of filter can be included in the payload.

### Simple filters (`[dataFilter]`)

`[dataFilter]` accepts an `Array<LinqPredicateDTO>`. Each `LinqPredicateDTO` contains a `PropertyFilters` array of `LinqFilterDTO` objects. Filters within the same `LinqPredicateDTO` are joined with AND; multiple `LinqPredicateDTO` objects are joined with OR.

```html
<eqp-lookup
  [entityType]="'City'"
  [fullUrlHttpCall]="fullUrlHttpCall"
  [dataFilter]="cityFilters"
  [formGroupInput]="myForm"
  [formControlNameInput]="'city'">
</eqp-lookup>
```

```ts
import { LinqPredicateDTO, LinqFilterDTO, LinqFilterType } from '@eqproject/eqp-lookup';

this.cityFilters = [
  {
    PropertyFilters: [
      LinqFilterDTO.createFilter('FK_Province', 10, LinqFilterType.Equal)
    ]
  }
];
```

Alternatively, pass the filter inline directly on the template as shown in Case 4.

### Complex filters (`[complexDataFilter]`)

`[complexDataFilter]` accepts an `Array<ComplexLinqPredicateDTO>`. Each `ComplexLinqPredicateDTO` wraps its own `Predicates` array, allowing groups of AND conditions to be combined with OR between groups. Use `ComplexLinqPredicateDTO.CreateComplexPredicate()` to build the structure from a matrix of `LinqPredicateDTO` arrays.

```ts
import { ComplexLinqPredicateDTO, LinqFilterDTO, LinqFilterType } from '@eqproject/eqp-lookup';

this.complexFilters = ComplexLinqPredicateDTO.CreateComplexPredicate([
  [
    { PropertyFilters: [LinqFilterDTO.createFilter('IsActive', true, LinqFilterType.Equal)] }
  ],
  [
    { PropertyFilters: [LinqFilterDTO.createFilter('FK_Category', 5, LinqFilterType.Equal)] }
  ]
]);
```

### Custom label composition (`[customConfig]`)

`[customConfig]` accepts a `LookupCustomConfig` object and instructs the server endpoint to build the `Label` property of each `LookupDTO` by concatenating the listed property names, and optionally to populate `FullObject` with the full entity.

```ts
this.customConfig = {
  LabelProperties: ['Name', 'Code', 'ID'],
  IncludeFullObject: true
};
```

When `IncludeFullObject` is true, the complete entity is available via `item.FullObject` inside custom templates and in the emitted value.


## Public methods

The following methods are available on `EqpLookupComponent` and can be accessed via `@ViewChild`.

```ts
@ViewChild(EqpLookupComponent) lookup: EqpLookupComponent;
```

| Method | Signature | Description |
| --- | --- | --- |
| `reloadData` | `reloadData(selectedItemID?: any): Promise<void>` | Reloads the datasource from `initialItems` or via HTTP and optionally pre-selects the item whose key matches `selectedItemID`. |
| `updateInitialItems` | `updateInitialItems(items: Array<LookupDTO>, selectedItemID?: any): void` | Replaces `initialItems` with a new array and triggers `reloadData`. Useful when the available options change at runtime. |
| `forceWriteValue` | `forceWriteValue(value: any): void` | Bypasses the normal change pipeline and directly calls `writeValue` on the underlying `NgSelectComponent`. Use this when the value must be set imperatively without emitting change events. |


## API

### Inputs

| Input                                       | Type                                                  | Default                      | Required | Description                                                                                                                           |
| ------------------------------------------- | ----------------------------------------------------- | ---------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| [placeholder]                               | `string`                                              | `-`                          | no       | Text displayed as placeholder when no item is selected. If `[isRequired]="true"`, an asterisk is appended automatically.             |
| [bindLabel]                                 | `string`                                              | `'Label'`                    | no       | Object property to use for label.                                                                                                     |
| [bindKey]                                   | `string`                                              | `'ID'`                       | no       | Object property to use for key.                                                                                                       |
| [items]                                     | `Array<objects>`                                      | `-`                          | no       | Array of objects that lookup will show.                                                                                               |
| [notFoundText]                              | `string`                                              | `'Nessun risultato trovato'` | no       | Custom text when filter returns empty result.                                                                                         |
| [genericAddComponent]                       | `DynamicLoaderDirectiveData`                          | `-`                          | no       | Object containing the component class, inputParams and other configuration parameters to add or edit elements via a modal dialog.     |
| [isMultiple]                                | `boolean`                                             | `false`                      | no       | Defines if the lookup can accept more values, managed like an object array.                                                           |
| [isSearchable]                              | `boolean`                                             | `true`                       | no       | Defines if it's possible to type inside lookup and search among items.                                                                |
| [isClearable]                               | `boolean`                                             | `true`                       | no       | Defines if the cancel button is shown.                                                                                                |
| [isVirtualScroll]                           | `boolean`                                             | `false`                      | no       | Dynamic render of the items contained in the lookup. Useful in case of huge amount of data.                                           |
| [isReadonly]                                | `boolean`                                             | `false`                      | no       | Set lookup as readonly.                                                                                                               |
| [isRequired]                                | `boolean`                                             | `false`                      | no       | Set lookup as required. Appends `*` to the placeholder text automatically.                                                            |
| [isDisabled]                                | `boolean`                                             | `false`                      | no       | Disable the lookup. Also respects `.disable()` called on the parent FormControl via ControlValueAccessor.                             |
| [entityType]                                | `string`                                              | `-`                          | yes      | Entity name to be searched on the server when the mode chosen isn't the one with `initialItems`.                                      |
| [formGroupInput]                            | `any`                                                 | `-`                          | no       | FormGroup that contains the specific FormControl of the lookup (to use if you're not using ngModelInput).                             |
| [formControlNameInput]                      | `any`                                                 | `-`                          | no       | FormControl to use inside the FormGroup passed (to use if you're not using ngModelInput).                                             |
| [ngModelInput]                              | `any`                                                 | `-`                          | no       | ngModel binded to lookup. (to use if you're not using FormControl)                                                                    |
| [isSearchWhileComposing]                    | `boolean`                                             | `false`                      | no       | Whether items should be filtered while composition started.                                                                           |
| [bindCompleteObject]                        | `boolean`                                             | `true`                       | no       | Whether the binded object must be ID or the full object.                                                                              |
| [appendToInput]                             | `string`                                              | `-`                          | no       | Input used when the lookup is contained inside a dialog or tab and there are visualization problems. Useful value: `body`. If omitted, the component auto-detects the context (dialog / tab / standard page) and sets the appropriate overlay target. |
| [disableReloadOnLookupAddingCompleteParent] | `boolean`                                             | `false`                      | no       | Whether data must be reloaded after adding is complete.                                                                               |
| [showOptionTooltip]                         | `boolean`                                             | `false`                      | no       | Defines if a tooltip must be shown on option hover.                                                                                   |
| [sortList]                                  | `boolean`                                             | `false`                      | no       | Items sorting based on Label.                                                                                                         |
| [dataFilter]                                | `Array<LinqPredicateDTO>`                             | `-`                          | no       | It allows you to pass some simple filters to the server (used when `fullUrlHttpCall` is also passed)                                  |
| [customConfig]                              | `LookupCustomConfig`                                  | `-`                          | no       | Configuration related to properties that compose the label and to full object inclusion (used when `fullUrlHttpCall` is also passed). |
| [complexDataFilter]                         | `Array<ComplexLinqPredicateDTO>`                      | `-`                          | no       | It allows you to pass some complex filters to the server (used when `fullUrlHttpCall` is also passed)                                 |
| [initialItems]                              | `Array<any>`                                          | `false`                      | no       | Initial datasource used if you want to bypass the server call.                                                                        |
| [ngModelOptions]                            | `any`                                                 | `-`                          | no       | Options related to ngModel.                                                                                                           |
| [isEditable]                                | `boolean`                                             | `false`                      | no       | Defines if the selected item can be edited. Requires `[genericAddComponent]` to be configured.                                        |
| [isMultiline]                               | `boolean`                                             | `false`                      | no       | Defines if the item selected's label can be shown inside a multiple line input.                                                       |
| [dropdownPosition]                          | `auto \| top \| bottom`                               | `auto`                       | no       | Specifies the position of the dropdown.                                                                                               |
| [selectOnTab]                               | `boolean`                                             | `false`                      | no       | Select marked dropdown item using tab.                                                                                                |
| [fullUrlHttpCall]                           | `string`                                              | `-`                          | no       | Full HTTP url for the server call.                                                                                                    |
| [addButtonText]                             | `string`                                              | `'Crea nuovo'`               | no       | Text displayed as tooltip when hovering on the add button.                                                                            |
| [editButtonText]                            | `string`                                              | `'Modifica'`                 | no       | Text displayed as tooltip when hovering on the edit button.                                                                           |
| [selectAll]                                 | `boolean`                                             | `false`                      | no       | Add an option inside the dropdown that allows the user to select all the elements.                                                    |
| [selectAllText]                             | `string`                                              | `'Seleziona tutto'`          | no       | Text displayed in the select all option.                                                                                              |
| [groupBy]                                   | `string \| Function`                                  | `-`                          | no       | Allow to group items by key or function expression.                                                                                   |
| [groupValue]                                | `(groupKey: string, children: any[]) => Object`       | `-`                          | no       | Function expression to provide group value.                                                                                           |
| [groupByProperty]                           | `string`                                              | `-`                          | no       | Property name used to group items. Required when `[selectableGroupAsModel]="true"` so that group selection can be exploded correctly. |
| [selectableGroup]                           | `boolean`                                             | `false`                      | no       | Allow to select group when groupBy is used.                                                                                           |
| [selectableGroupAsModel]                    | `boolean`                                             | `false`                      | no       | Indicates whether to select all children or group itself. When true, group selection is automatically "exploded" into its individual child items before being emitted via the change outputs. |
| [clearAllText]                              | `string`                                              | `'Elimina'`                  | no       | Text displayed as tooltip when hovering the clear button.                                                                             |
| [customOption]                              | `TemplateRef`                                         | `-`                          | no       | Custom template for the option inside the dropdown panel.                                                                             |
| [customLabel]                               | `TemplateRef`                                         | `-`                          | no       | Custom template for the selected item's label.                                                                                        |
| [manipulateDataFn]                          | `(items: any) =>  LookupDTO[]`                        | `-`                          | no       | Function to manipulate data after the HTTP call used to retrieve items.                                                               |
| [compareFunction]                           | `(iteratedObject: any, bindedObject: any) => boolean` | `-`                          | no       | Function to compare the option values with the selected values. A boolean should be returned. By default the component uses a smart comparison that handles both primitive values and objects by comparing the `Key` or `bindKey` property. |
| [selectFirstItem]                           | `boolean`                                             | `false`                      | no       | Property that allows to select the first item of the lookup if there is not already a selection.                                      |
| [selectIfSingleItem]                        | `boolean`                                             | `false`                      | no       | Property that allows to select the only item of the lookup if there is only one item and there is not already a selection.            |
| [initialSelectedID]                         | `any`                                                 | `-`                          | no       | ID (or a value of the BindKey selected) that allows to select the corresponding item of the lookup during the Init of the component.  |
| [appearance]                                | `string`                                              | `''`                         | no       | Defines the Angular Material form field appearance. Accepted values are those defined by Angular Material: `'outline'`, `'fill'`. When empty the default Material theme from ng-select is used. |

### Outputs

| Output                       | Event arguments | Required | Description                                                                                                           |
| ---------------------------- | --------------- | -------- | --------------------------------------------------------------------------------------------------------------------- |
| (ngModelInputChange)         | `any`           | `-`      | Invoked when the value changes and the ngModelInput is binded. When items are grouped it return the group 'exploded'. |
| (formControlChange)          | `any`           | `-`      | Invoked when the value changes and a form control is binded. When items are grouped it return the group 'exploded'.   |
| (lookupAddingCompleteParent) | `any`           | `-`      | Event emitted when the add process is completed and disableReloadOnLookupAddingCompleteParent is not true.            |
| (searchChange)               | `any`           | `-`      | Invoked when user searches among lookup items. It return the term typed and items filtered.                           |
| (keydown)                    | `any`           | `-`      | Invoked on keydown.                                                                                                   |
| (clear)                      | `any`           | `-`      | Event emitted on select clear.                                                                                        |
| (valueSelected)              | `LookupDTO`     | `-`      | Event emitted when a value is selected.                                                                               |
| (itemsUpdated)               | `LookupDTO[]`   | `-`      | Event emitted when the list of items of the lookup is updated (after every `reloadData` call).                        |


## Models

### LookupDTO

The standard data transfer object returned by the server endpoint and used internally throughout the component.

| Property    | Type                            | Description                                                                                  |
| ----------- | ------------------------------- | -------------------------------------------------------------------------------------------- |
| ID          | `number \| string \| null`      | Unique identifier of the item. Corresponds to the `[bindKey]` property (default `'ID'`).    |
| Label       | `string \| null`                | Display text of the item. Corresponds to the `[bindLabel]` property (default `'Label'`).    |
| FullObject  | `any`                           | Full entity object, populated when `LookupCustomConfig.IncludeFullObject` is true.           |

### LookupCustomConfig

Passed via `[customConfig]` to control how the server builds each `LookupDTO.Label` and whether the full entity is included.

| Property          | Type               | Description                                                                                                      |
| ----------------- | ------------------ | ---------------------------------------------------------------------------------------------------------------- |
| LabelProperties   | `Array<string>`    | List of entity property names whose values are concatenated (in order) to form the `Label` of each `LookupDTO`. |
| IncludeFullObject | `boolean`          | If true, the server populates `LookupDTO.FullObject` with the complete entity.                                   |

### DynamicLoaderDirectiveData

Passed via `[genericAddComponent]` to configure the inline add/edit modal.

| Property                | Type                            | Default     | Description                                                                                                                                               |
| ----------------------- | ------------------------------- | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| componentSelector       | `any`                           | -           | The Angular component class to dynamically load inside the modal.                                                                                         |
| inputParams             | `any`                           | `null`      | Optional object whose keys are mapped to properties of the loaded component instance.                                                                     |
| idLookupEntity          | `number \| null`                | `null`      | ID of the entity to edit. Pass `null` or `0` for creation mode. The lookup updates this value automatically after a successful save.                      |
| isEditable              | `boolean`                       | `false`     | N.D.                                                                                                                                                      |
| disableRedirectAfterSave| `boolean`                       | `undefined` | If true, sets `disableRedirectAfterSave = true` on the loaded component. The component must expose this property or a runtime error is thrown.             |

### LinqPredicateDTO / LinqFilterDTO / LinqFilterType

Used with `[dataFilter]` to build server-side filter conditions.

```ts
import { LinqPredicateDTO, LinqFilterDTO, LinqFilterType } from '@eqproject/eqp-lookup';

// Shorthand factory method
const filter = LinqFilterDTO.createFilter('IsActive', true, LinqFilterType.Equal);

const predicate: LinqPredicateDTO = { PropertyFilters: [filter] };
```

**LinqFilterType enum values:**

| Value | Name                 | Description                                       |
| ----- | -------------------- | ------------------------------------------------- |
| 1     | Equal                | Property equals value                             |
| 2     | NotEqual             | Property does not equal value                     |
| 3     | StringContains       | String property contains value                    |
| 4     | StringNotContains    | String property does not contain value            |
| 5     | GreaterThan          | Property is greater than value                    |
| 6     | GreaterThanOrEqual   | Property is greater than or equal to value        |
| 7     | LessThan             | Property is less than value                       |
| 8     | LessThanOrEqual      | Property is less than or equal to value           |
| 9     | ContainsElement      | Collection property contains element              |
| 10    | NotContainsElement   | Collection property does not contain element      |

**LinqFilterDTO properties:**

| Property                | Type              | Description                                                                                    |
| ----------------------- | ----------------- | ---------------------------------------------------------------------------------------------- |
| PropertyName            | `string`          | Name of the entity property to filter on.                                                     |
| PropertyValue           | `any`             | Value to compare against.                                                                      |
| RelationType            | `LinqFilterType`  | Comparison operator.                                                                           |
| ListElementPropertyName | `string \| null`  | Optional. Used when filtering on a property of an element inside a collection property.        |

### ComplexLinqPredicateDTO

Used with `[complexDataFilter]` to build groups of AND conditions joined by OR.

```ts
import { ComplexLinqPredicateDTO, LinqFilterDTO, LinqFilterType } from '@eqproject/eqp-lookup';

const complexFilters = ComplexLinqPredicateDTO.CreateComplexPredicate([
  // Group 1 (AND between filters)
  [{ PropertyFilters: [LinqFilterDTO.createFilter('IsActive', true, LinqFilterType.Equal)] }],
  // Group 2 (OR with Group 1)
  [{ PropertyFilters: [LinqFilterDTO.createFilter('FK_Category', 5, LinqFilterType.Equal)] }]
]);
```


## Use cases

### Case 1: Lookup with initial items :

```html
<eqp-lookup
  placeholder="Lookup with initial items"
  [entityType]="'Question'"
  [initialItems]="questionInitialItems"
  [formGroupInput]="lookupFormGroup"
  [formControlNameInput]="'lookupWithInitialItems'"
  (formControlChange)="lookupChange($event)"></eqp-lookup>
```

Define properties and functions in Typescript (or Javascript) file

```ts
lookupFormGroup : FormGroup | undefined;

...

createForm() {
	this.lookupFormGroup = this.formBuilder.group({
		lookupWithInitialItems: [null, Validators.required],
	})
}

...

this.http.post<LookupDTO[]>(url, config).subscribe(res  => {
	this.questionInitialItems = res;
})

...

lookupChange(event: any) {
	// body
}
```

### Case 2: Lookup with HTTP call and ngModelInput :

Define component selector in HTML

```html
<eqp-lookup
  placeholder="Lookup with HTTP call"
  [entityType]="'Question'"
  [fullUrlHttpCall]="fullUrlHttpCall"
  [(ngModelInput)]="lookupWithHttpCall"
  (ngModelInputChange)="lookupChange($event)"
  [isMultiline]="true"></eqp-lookup>
```

Define properties and functions in Typescript (or Javascript) file

```ts
fullUrlHttpCall = environment.apiFullUrl + '/lookup/GetLookupEntities';
lookupWithHttpCall: LookupDTO | undefined;

...

lookupChange(event: any) {
	// body
}
```

### Case 3: Lookup with HTTP call and Form :

Define component selector in HTML

```html
<eqp-lookup
  placeholder="Lookup with aform"
  [entityType]="'Question'"
  [fullUrlHttpCall]="fullUrlHttpCall"
  [formGroupInput]="lookupFormGroup"
  [formControlNameInput]="'lookupWithForm'"
  (formControlChange)="lookupChange($event)"
  [isMultiline]="true"></eqp-lookup>
```

Define properties and functions in Typescript (or Javascript) file

```ts
fullUrlHttpCall = environment.apiFullUrl + '/lookup/GetLookupEntities';
lookupFormGroup : FormGroup | undefined;
...

createForm() {
	this.lookupFormGroup = this.formBuilder.group({
		lookupWithForm: [null, Validators.required],
	})
}

...

lookupChange(event: any) {
	// body
}
```

### Case 4: Lookup with HTTP call and extra configs :

Define component selector in HTML

```html
<eqp-lookup
  [entityType]="'City'"
  placeholder="Città"
  [fullUrlHttpCall]="fullUrlHttpCall"
  [formGroupInput]="lookupFormGroup"
  [formControlNameInput]="'lookupWithExtraConfigs'"
  (formControlChange)="lookupChange($event)"
  [dataFilter]="[{PropertyFilters: [{PropertyName: 'FK_Province', PropertyValue: 10, RelationType: 1}]}]"
  [customConfig]="{LabelProperties: ['Name', 'Code', 'ID'], IncludeFullObject: true}"></eqp-lookup>
```

Define properties and functions in Typescript (or Javascript) file

```ts
fullUrlHttpCall = environment.apiFullUrl + '/lookup/GetLookupEntities';
lookupFormGroup : FormGroup | undefined;

...

createForm() {
	this.lookupFormGroup = this.formBuilder.group({
		lookupWithExtraConfigs: [null, Validators.required],
	})
}

...

lookupChange(event: any) {
	// body
}
```

### Case 5: Editable Lookup :

Define component selector in HTML

```html
<eqp-lookup
  placeholder="Editable lookup"
  [entityType]="'Question'"
  [fullUrlHttpCall]="fullUrlHttpCall"
  [genericAddComponent]="{componentSelector: addQuestionComponent, idLookupEntity: getNumber(getFormControls('editableLookup').value), isEditable: true, disableRedirectAfterSave: true}"
  [isVirtualScroll]="true"
  [formGroupInput]="lookupFormGroup"
  [formControlNameInput]="'editableLookup'"
  (formControlChange)="lookupChange($event)"
  [isMultiline]="true"
  [isEditable]="true"></eqp-lookup>
```

Define properties and functions in Typescript (or Javascript) file

```ts
fullUrlHttpCall = environment.apiFullUrl + '/lookup/GetLookupEntities';
lookupFormGroup : FormGroup | undefined;
addQuestionComponent = AddQuestionComponent;
...

createForm() {
	this.lookupFormGroup = this.formBuilder.group({
		editableLookup: [null, Validators.required],
	})
}

...

getNumber(element: number | string | undefined | null): number | null {
	if (element != null)
		return  Number(element);
	else
		return  <null><unknown>  element;
}

...

getFormControls(control: string) {
	return  this.lookupFormGroup.controls[control];
}

...

lookupChange(event: any) {
	// body
}
```

### Case 6: Lookup with select all :

Define component selector in HTML

```html
<eqp-lookup
  placeholder="Lookup with select all"
  [entityType]="'Question'"
  [fullUrlHttpCall]="fullUrlHttpCall"
  [isVirtualScroll]="true"
  (formControlChange)="lookupChange($event)"
  [formGroupInput]="lookupFormGroup"
  [formControlNameInput]="'lookupWithSelectAll'"
  [isMultiline]="true"
  [isEditable]="true"
  [selectAll]="true"
  [isMultiple]="true"
  [selectableGroupAsModel]="true"></eqp-lookup>
```

Define properties and functions in Typescript (or Javascript) file

```ts
fullUrlHttpCall = environment.apiFullUrl + '/lookup/GetLookupEntities';
lookupFormGroup : FormGroup | undefined;
...

createForm() {
	this.lookupFormGroup = this.formBuilder.group({
		lookupWithSelectAll: [null, Validators.required],
	})
}

...

lookupChange(event: any) {
	// body
}
```

### Case 7: Lookup with groups :

Define component selector in HTML

```html
<eqp-lookup
  placeholder="Lookup with groups"
  [entityType]="'Question'"
  [fullUrlHttpCall]="fullUrlHttpCall"
  [isVirtualScroll]="true"
  [formGroupInput]="lookupFormGroup"
  [formControlNameInput]="'lookupWithGroups'"
  (formControlChange)="lookupChange($event)"
  [isMultiline]="true"
  [groupBy]="groupByFn"
  [groupValue]="groupValueFn"
  [groupByProperty]="'FullObject.FK_QuestionCategory'"
  [isMultiple]="true"
  [selectableGroup]="true"
  [selectableGroupAsModel]="true"></eqp-lookup>
```

Define properties and functions in Typescript (or Javascript) file

```ts
fullUrlHttpCall = environment.apiFullUrl + '/lookup/GetLookupEntities';
lookupFormGroup : FormGroup | undefined;
groupByFn = (item: any) =>  item.FullObject.FK_QuestionCategory
groupValueFn = (groupKey: string, children: any[]) => ({Key:  groupKey, Label:  groupKey, Total:  children.length});
...

createForm() {
	this.lookupFormGroup = this.formBuilder.group({
		lookupWithGroups: [null, Validators.required],
	})
}

...

lookupChange(event: any) {
	// body
}
```

NB: It's possible to change the Label displayed for groups passing some values or using the `groupKey` to access the selected properties inside an array.

### Case 8: Lookup with data manipulation and custom templates :

Define component selector in HTML

```html
<eqp-lookup
  placeholder="Lookup with function and custom templates"
  [entityType]="'Question'"
  [fullUrlHttpCall]="fullUrlHttpCall"
  [formGroupInput]="lookupFormGroup"
  [formControlNameInput]="'lookupWithFunctionAndCustomTemplates'"
  (formControlChange)="lookupChange($event)"
  [isMultiline]="true"
  [selectAll]="true"
  [customOption]="customOptionTemplate"
  [customLabel]="customLabelTemplate"
  [manipulateDataFn]="manipulateData"></eqp-lookup>
```

Define custom templates in HTML

```html
<!-- Template for option inside the dropdown panel -->
<ng-template #customOptionTemplate ng-option-tmp let-item="item" let-index="index" let-search="searchTerm">
  <div class="card">
    <div class="card-body">
      <h5 class="card-title">{{item.Label}}</h5>
      <h6 class="card-subtitle mb-2 text-muted">Card subtitle</h6>
      <p class="card-text">Some quick example text to build</p>
      <div>
        <a href="#" class="card-link">Card link</a>
        <a href="#" class="card-link">Another link</a>
      </div>
    </div>
  </div>
</ng-template>

<!-- Selected items' Label template -->
<ng-template #customLabelTemplate ng-label-tmp let-item="item" let-clear="clear">
  <span title="{{item.Label}}">Custom template: {{item.Label}}</span>
  <span *ngIf="item.Total" class="ml-1 badge badge-secondary" style="color: black !important">{{item.Total}}</span>
  <span class="ng-value-icon right" (click)="clear(item)" aria-hidden="true"> x </span>
</ng-template>
```

Define properties and functions in Typescript (or Javascript) file

```ts
fullUrlHttpCall = environment.apiFullUrl + '/lookup/GetLookupEntities';
lookupFormGroup : FormGroup | undefined;
@ViewChild("customOptionTemplate") customOptionTemplate: TemplateRef<any>;
@ViewChild("customLabelTemplate") customLabelTemplate: TemplateRef<any>;
...

createForm() {
	this.lookupFormGroup = this.formBuilder.group({
		lookupWithFunctionAndCustomTemplates: [null, Validators.required],
	})
}

manipulateData(items: any) : LookupDTO[] {
	let  res: LookupDTO[] = [];
	for(let  item  of  items) {
		item.Label += " added later";
		res.push(item)
	}
	return  res;
}

...

lookupChange(event: any) {
	// body
}
```

### Case 9: Lookup with runtime datasource update :

Use `updateInitialItems` to replace the datasource at runtime without having to re-configure the component. This is useful when the available options depend on the selection made in another field.

```html
<eqp-lookup
  #cityLookup
  placeholder="City"
  [entityType]="'City'"
  [initialItems]="cities"
  [formGroupInput]="myForm"
  [formControlNameInput]="'city'"
  (formControlChange)="onCityChange($event)">
</eqp-lookup>
```

```ts
@ViewChild('cityLookup') cityLookup: EqpLookupComponent;

onProvinceChange(province: any) {
  // Filter cities based on selected province
  const filtered = this.allCities.filter(c => c.FK_Province === province.ID);
  // Replace the datasource and reset the selection
  this.cityLookup.updateInitialItems(filtered);
}
```

### Case 10: Lookup with complex server-side filters :

Use `[complexDataFilter]` when the server filter requires groups of AND conditions joined by OR.

```html
<eqp-lookup
  placeholder="Prodotto"
  [entityType]="'Product'"
  [fullUrlHttpCall]="fullUrlHttpCall"
  [complexDataFilter]="productFilters"
  [formGroupInput]="myForm"
  [formControlNameInput]="'product'"
  (formControlChange)="onProductChange($event)">
</eqp-lookup>
```

```ts
import { ComplexLinqPredicateDTO, LinqFilterDTO, LinqFilterType } from '@eqproject/eqp-lookup';

// Selects products that are either active OR belong to category 5
this.productFilters = ComplexLinqPredicateDTO.CreateComplexPredicate([
  [{ PropertyFilters: [LinqFilterDTO.createFilter('IsActive', true, LinqFilterType.Equal)] }],
  [{ PropertyFilters: [LinqFilterDTO.createFilter('FK_Category', 5, LinqFilterType.Equal)] }]
]);
```

## Credits

This library has been developed by EqProject SRL, for more info contact: info@eqproject.it

---
_Source: https://npm.io/package/@eqproject/eqp-lookup · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
