Angular Lookup - Getting Started
Drop-down editors allow users to navigate through a list of items, select one or multiple items, and search through the list. To learn how to choose a DevExtreme drop-down editor and for more details about the component's features, refer to the following article: How to Choose a Drop-Down Editor.
jQuery
Angular
Vue
React
Lookup is a component that allows users to search and select an item in the drop-down list.
This tutorial shows how to add a Lookup component to your application, bind it to data, and configure its core features.
Each section in this tutorial describes a single configuration step. You can also find the full code in the following GitHub repository: getting-started-with-lookup.
Create a Lookup Component
jQuery
Add DevExtreme to your jQuery application and use the following code to create a Lookup component:
$(function() { $("#lookup").dxLookup({ }); });
<html> <head> <!-- ... --> <script type="text/javascript" src="https://code.jquery.com/jquery-3.5.1.min.js"></script> <link rel="stylesheet" href="https://cdn3.devexpress.com/jslib/23.1.13/css/dx.light.css"> <script type="text/javascript" src="https://cdn3.devexpress.com/jslib/23.1.13/js/dx.all.js"></script> <script type="text/javascript" src="index.js"></script> </head> <body> <div id="lookup"></div> </body> </html>
Angular
Add DevExtreme to your Angular application and use the following code to create a Lookup component:
<dx-lookup></dx-lookup>
import { Component } from '@angular/core'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { }
import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { AppComponent } from './app.component'; import { DxLookupModule } from 'devextreme-angular'; @NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, DxLookupModule ], providers: [ ], bootstrap: [AppComponent] }) export class AppModule { }
Vue
Add DevExtreme to your Vue application and use the following code to create a Lookup component:
<template> <DxLookup> </DxLookup> </template> <script> import 'devextreme/dist/css/dx.light.css'; import { DxLookup } from 'devextreme-vue/lookup'; export default { components: { DxLookup } } </script>
React
Add DevExtreme to your React application and use the following code to create a Lookup component:
import React from 'react'; import 'devextreme/dist/css/dx.light.css'; import { Lookup } from 'devextreme-react/lookup'; function App() { return ( <Lookup> </Lookup> ); } export default App;
Bind Lookup to Data
Lookup can load data from different data source types. To use a local array, assign it to the dataSource property. If array elements are objects, specify the fields that supply Lookup's value (valueExpr) and displayed value (displayExpr). For information on other data source types, refer to the following articles:
jQuery
$(function() { $("#lookup").dxLookup({ dataSource: new DevExpress.data.DataSource({ store: employeesTasks, key: "ID" }), valueExpr: "ID", displayExpr: "Subject" }); });
<head> <!-- ... --> <script type="text/javascript" src="data.js"></script> </head>
const employeesTasks = [ { ID: 1, Assignee: "Mr. John Heart", Subject: "Choose between PPO and HMO Health Plan", disabled: true }, { ID: 2, Assignee: "Mr. John Heart", Subject: "Google AdWords Strategy" }, { ID: 3, Assignee: "Mr. John Heart", Subject: "New Brochures" }, { ID: 4, Assignee: "Mr. John Heart", Subject: "Update NDA Agreement" }, { ID: 5, Assignee: "Mr. John Heart", Subject: "Review Product Recall Report by Engineering Team" }, { ID: 6, Assignee: "Mrs. Olivia Peyton", Subject: "Update Personnel Files" }, { ID: 7, Assignee: "Mrs. Olivia Peyton", Subject: "Review Health Insurance Options Under the Affordable Care Act" }, { ID: 8, Assignee: "Mrs. Olivia Peyton", Subject: "Non-Compete Agreements" }, { ID: 9, Assignee: "Mrs. Olivia Peyton", Subject: "Give Final Approval for Refunds" }, { ID: 10, Assignee: "Mr. Robert Reagan", Subject: "Deliver R&D Plans for 2013" }, { ID: 11, Assignee: "Mr. Robert Reagan", Subject: "Decide on Mobile Devices to Use in the Field" }, { ID: 12, Assignee: "Mr. Robert Reagan", Subject: "Try New Touch-Enabled WinForms Apps" }, { ID: 13, Assignee: "Mr. Robert Reagan", Subject: "Approval on Converting to New HDMI Specification" }, { ID: 14, Assignee: "Ms. Greta Sims", Subject: "Approve Hiring of John Jeffers" }, { ID: 15, Assignee: "Ms. Greta Sims", Subject: "Update Employee Files with New NDA" }, { ID: 16, Assignee: "Ms. Greta Sims", Subject: "Provide New Health Insurance Docs" } ];
Angular
<dx-lookup [dataSource]="dataSource" valueExpr="ID" displayExpr="Subject"> </dx-lookup>
import { Component } from '@angular/core'; import { AppService, Task } from './app.service'; import DataSource from 'devextreme/data/data_source'; // ... export class AppComponent { employeesTasks: Task[]; dataSource: DataSource; constructor(service: AppService) { this.employeesTasks = service.getTasks(); this.dataSource = new DataSource({ store: this.employeesTasks, key: "ID" }); } }
import { Injectable } from '@angular/core'; export class Task { ID: number; Assignee: string; Subject: string; disabled?: boolean; } const employeesTasks: Task[] = [ { ID: 1, Assignee: "Mr. John Heart", Subject: "Choose between PPO and HMO Health Plan", disabled: true }, { ID: 2, Assignee: "Mr. John Heart", Subject: "Google AdWords Strategy" }, { ID: 3, Assignee: "Mr. John Heart", Subject: "New Brochures" }, { ID: 4, Assignee: "Mr. John Heart", Subject: "Update NDA Agreement" }, { ID: 5, Assignee: "Mr. John Heart", Subject: "Review Product Recall Report by Engineering Team" }, { ID: 6, Assignee: "Mrs. Olivia Peyton", Subject: "Update Personnel Files" }, { ID: 7, Assignee: "Mrs. Olivia Peyton", Subject: "Review Health Insurance Options Under the Affordable Care Act" }, { ID: 8, Assignee: "Mrs. Olivia Peyton", Subject: "Non-Compete Agreements" }, { ID: 9, Assignee: "Mrs. Olivia Peyton", Subject: "Give Final Approval for Refunds" }, { ID: 10, Assignee: "Mr. Robert Reagan", Subject: "Deliver R&D Plans for 2013" }, { ID: 11, Assignee: "Mr. Robert Reagan", Subject: "Decide on Mobile Devices to Use in the Field" }, { ID: 12, Assignee: "Mr. Robert Reagan", Subject: "Try New Touch-Enabled WinForms Apps" }, { ID: 13, Assignee: "Mr. Robert Reagan", Subject: "Approval on Converting to New HDMI Specification" }, { ID: 14, Assignee: "Ms. Greta Sims", Subject: "Approve Hiring of John Jeffers" }, { ID: 15, Assignee: "Ms. Greta Sims", Subject: "Update Employee Files with New NDA" }, { ID: 16, Assignee: "Ms. Greta Sims", Subject: "Provide New Health Insurance Docs" } ]; @Injectable() export class AppService { getTasks(): Task[] { return employeesTasks; } }
Vue
<template> <DxLookup :data-source="dataSource" value-expr="ID" display-expr="Subject" /> </template> <script> // ... import DataSource from 'devextreme/data/data_source'; import { employeesTasks } from './data'; const dataSource = new DataSource({ store: employeesTasks, key: "ID" }); export default { components: { DxLookup }, data() { return { dataSource } } } </script>
export const employeesTasks = [ { ID: 1, Assignee: "Mr. John Heart", Subject: "Choose between PPO and HMO Health Plan", disabled: true }, { ID: 2, Assignee: "Mr. John Heart", Subject: "Google AdWords Strategy" }, { ID: 3, Assignee: "Mr. John Heart", Subject: "New Brochures" }, { ID: 4, Assignee: "Mr. John Heart", Subject: "Update NDA Agreement" }, { ID: 5, Assignee: "Mr. John Heart", Subject: "Review Product Recall Report by Engineering Team" }, { ID: 6, Assignee: "Mrs. Olivia Peyton", Subject: "Update Personnel Files" }, { ID: 7, Assignee: "Mrs. Olivia Peyton", Subject: "Review Health Insurance Options Under the Affordable Care Act" }, { ID: 8, Assignee: "Mrs. Olivia Peyton", Subject: "Non-Compete Agreements" }, { ID: 9, Assignee: "Mrs. Olivia Peyton", Subject: "Give Final Approval for Refunds" }, { ID: 10, Assignee: "Mr. Robert Reagan", Subject: "Deliver R&D Plans for 2013" }, { ID: 11, Assignee: "Mr. Robert Reagan", Subject: "Decide on Mobile Devices to Use in the Field" }, { ID: 12, Assignee: "Mr. Robert Reagan", Subject: "Try New Touch-Enabled WinForms Apps" }, { ID: 13, Assignee: "Mr. Robert Reagan", Subject: "Approval on Converting to New HDMI Specification" }, { ID: 14, Assignee: "Ms. Greta Sims", Subject: "Approve Hiring of John Jeffers" }, { ID: 15, Assignee: "Ms. Greta Sims", Subject: "Update Employee Files with New NDA" }, { ID: 16, Assignee: "Ms. Greta Sims", Subject: "Provide New Health Insurance Docs" } ];
React
// ... import DataSource from 'devextreme/data/data_source'; import { employeesTasks } from './data'; const dataSource = new DataSource({ store: employeesTasks, key: "ID" }); function App() { return ( <Lookup dataSource={dataSource} valueExpr="ID" displayExpr="Subject" /> ); } export default App;
export const employeesTasks = [ { ID: 1, Assignee: "Mr. John Heart", Subject: "Choose between PPO and HMO Health Plan", disabled: true }, { ID: 2, Assignee: "Mr. John Heart", Subject: "Google AdWords Strategy" }, { ID: 3, Assignee: "Mr. John Heart", Subject: "New Brochures" }, { ID: 4, Assignee: "Mr. John Heart", Subject: "Update NDA Agreement" }, { ID: 5, Assignee: "Mr. John Heart", Subject: "Review Product Recall Report by Engineering Team" }, { ID: 6, Assignee: "Mrs. Olivia Peyton", Subject: "Update Personnel Files" }, { ID: 7, Assignee: "Mrs. Olivia Peyton", Subject: "Review Health Insurance Options Under the Affordable Care Act" }, { ID: 8, Assignee: "Mrs. Olivia Peyton", Subject: "Non-Compete Agreements" }, { ID: 9, Assignee: "Mrs. Olivia Peyton", Subject: "Give Final Approval for Refunds" }, { ID: 10, Assignee: "Mr. Robert Reagan", Subject: "Deliver R&D Plans for 2013" }, { ID: 11, Assignee: "Mr. Robert Reagan", Subject: "Decide on Mobile Devices to Use in the Field" }, { ID: 12, Assignee: "Mr. Robert Reagan", Subject: "Try New Touch-Enabled WinForms Apps" }, { ID: 13, Assignee: "Mr. Robert Reagan", Subject: "Approval on Converting to New HDMI Specification" }, { ID: 14, Assignee: "Ms. Greta Sims", Subject: "Approve Hiring of John Jeffers" }, { ID: 15, Assignee: "Ms. Greta Sims", Subject: "Update Employee Files with New NDA" }, { ID: 16, Assignee: "Ms. Greta Sims", Subject: "Provide New Health Insurance Docs" } ];
Configure Search
Lookup allows users to search through the drop-down list. To configure the search, set the following properties:
searchMode: "contains" | "startswith"
Specifies the comparison operation used to search Lookup items.searchExpr
Specifies data fields or an expression against which the component compares the search criteria.minSearchLength
Specifies the minimum number of characters that users should enter into the text box to begin a search.showDataBeforeSearch
Specifies whether the UI component displays unfiltered values until users types the number of characters that exceed the minSearchLength property value.
To disable the search, set the searchEnabled property to false.
In the following code, the searchMode property is set to "contains". This mode allows users to find items that contain the search value. The searchExpr property is set to an array of two data fields to searches both fields. The minSearchLength property indicates that the search begins only when users type two or more characters. The showDataBeforeSearch property is set to true, and the component shows items before the search starts.
jQuery
$(function() { $("#lookup").dxLookup({ // ... searchMode: "contains", searchExpr: ['Assignee', 'Subject'], minSearchLength: 2, showDataBeforeSearch: true }); });
Angular
<dx-lookup ... searchMode="contains" [searchExpr]="['Assignee', 'Subject']" [minSearchLength]="2" [showDataBeforeSearch]="true"> </dx-lookup>
Vue
<template> <DxLookup ... search-mode="contains" :search-expr="['Assignee', 'Subject']" :min-search-length="2" :show-data-before-search="true" /> </template> <script> // ... </script>
React
// ... const searchExpression = ['Assignee', 'Subject']; function App() { return ( <Lookup ... searchMode="contains" searchExpr={searchExpression} minSearchLength={2} showDataBeforeSearch={true} /> ); } export default App;
Handle the Value Change Event
Implement the onValueChanged handler to perform an action when a user selects an item. In the code below, this function logs the IDs of the currently and previously selected items.
jQuery
$(function() { $("#lookup").dxLookup({ // ... onValueChanged: function(e) { console.log(e.value); console.log(e.previousValue); }, }); });
Angular
<dx-lookup ... (onValueChanged)="onValueChanged($event)"> </dx-lookup>
import { Component } from '@angular/core'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { // ... onValueChanged(e) { console.log(e.previousValue); console.log(e.value); } }
Vue
<template> <DxLookup ... @value-changed="onValueChanged" /> </template> <script> export default { // ... methods: { onValueChanged(e) { console.log(e.previousValue); console.log(e.value); } } } </script>
React
import React, { useCallback } from 'react'; function App() { const onValueChanged = useCallback((e) => { console.log(e.previousValue); console.log(e.value); }, []); return ( <Lookup ... onValueChanged={onValueChanged} /> ); } export default App;
Group Data
You can group data by category in Lookup. To implement this, we use data from the previous steps with the DataSource component that allows you to sort, filter, select, and group data.
Use the DataSource's group property to specify the data field to group by and enable Lookup's grouped property to notify the component that the data source is grouped.
jQuery
$(function() { $("#lookup").dxLookup({ dataSource: new DevExpress.data.DataSource({ // ... group: "Assignee" }), // ... grouped: true }); });
Angular
<dx-lookup ... [grouped]="true"> </dx-lookup>
// ... export class AppComponent { // ... constructor(service: Service) { // ... this.dataSource = new DataSource({ // ... group: "Assignee" }); } }
Vue
<template> <DxLookup ... :grouped="true" /> </template> <script> // ... const dataSource = new DataSource({ // ... group: "Assignee" }); </script>
React
// ... const dataSource = new DataSource({ // ... group: "Assignee" }); function App() { return ( <Lookup ... grouped={true} /> ); } export default App;
To customize the appearance of group titles, use groupTemplate.
jQuery
$(function() { $("#lookup").dxLookup({ // ... groupTemplate: function (data, index, element) { return data.key + " (" + data.items.length + " tasks)"; }, }); });
Angular
<dx-lookup ... groupTemplate="listGroup"> <!-- ... --> <div *dxTemplate="let data of 'listGroup'"> {{ data.key + " (" + data.items.length + " tasks)" }} </div> </dx-lookup>
Vue
<template> <DxLookup ... group-template="group-list"> <template #group-list="{ data }"> {{ data.key + " (" + data.items.length + " tasks)" }} </template> </DxLookup> </template> <script> // ... </script>
React
// ... const renderListGroup = (data) => { return ( <div>{ data.key + " (" + data.items.length + " tasks)" }</div> ); } function App() { return ( <Lookup ... groupRender={renderListGroup} /> ); } export default App;
Enable Pagination
Pagination allows Lookup to render items in batches. When data is remote, the component can also load items in batches if the server can partition data. Follow the steps below to enable this functionality:
Set the DataSource's paginate property to true.
Use the DataSource's pageSize property to specify the number of visible items on one page. If you group data, the pageSize specifies the number of groups.
Lookup renders the next page when users scroll the drop-down list to the bottom or when they click the "Next" button. To specify this behavior, set the Lookup's pageLoadMode property to "nextButton". Additionally, you can specify the nextButtonText property if you want to rename the "Next" button.
jQuery
$(function() { $("#lookup").dxLookup({ dataSource: new DevExpress.data.DataSource({ // ... paginate: true, pageSize: 2 }), // ... pageLoadMode: "nextButton", nextButtonText: "More" }); });
Angular
<dx-lookup ... pageLoadMode="nextButton" nextButtonText="More"> </dx-lookup>
// ... export class AppComponent { // ... constructor(service: AppService) { // ... this.dataSource = new DataSource({ // ... paginate: true, pageSize: 2 }); } }
Vue
<template> <DxLookup ... page-load-mode="nextButton" next-button-text="More" /> </template> <script> // ... const dataSource = new DataSource({ // ... paginate: true, pageSize: 2 }); </script>
React
// ... const dataSource = new DataSource({ // ... paginate: true, pageSize: 2 }); function App() { return ( <Lookup ... pageLoadMode="nextButton" nextButtonText="More" /> ); } export default App;
Customize Item Appearance
To customize item appearance, use itemTemplate.
jQuery
$(function() { $("#lookup").dxLookup({ // ... itemTemplate: function (itemData, itemIndex, itemElement) { return itemData.disabled ? '\u274C ' + itemData.Subject : '\u2705 ' + itemData.Subject; } }); });
Angular
<dx-lookup ... itemTemplate="listItem"> <!-- ... --> <div *dxTemplate="let itemData of 'listItem'"> {{ itemData.disabled ? '\u274C ' + itemData.Subject : '\u2705 ' + itemData.Subject }} </div> </dx-lookup>
Vue
<template> <DxLookup ... item-template="list-item"> <template #list-item="{ data: itemData }"> {{ itemData.disabled ? '\u274C ' + itemData.Subject : '\u2705 ' + itemData.Subject }} </template> </DxLookup> </template> <script> // ... </script>
React
// ... const renderListItem = (data) => { return ( <div>{ data.disabled ? '\u274C ' + data.Subject : '\u2705 ' + data.Subject }</div> ); } function App() { return ( <Lookup ... itemRender={renderListItem} /> ); } export default App;
Customize the Drop-Down Menu
On desktops and iOS devices, the Lookup's drop-down menu is the Popover UI component; on other devices, it is the Popup component.
To customize Popup or Popover, use the dropDownOptions object. For example, the following code closes Lookup when users click outside and removes the item list title:
jQuery
$(function() { $("#lookupContainer").dxLookup({ // ... dropDownOptions: { hideOnOutsideClick: true, showTitle: false } }); });
Angular
<dx-lookup> <dxo-drop-down-options [hideOnOutsideClick]="true" [showTitle]="false"> </dxo-drop-down-options> </dx-lookup>
Vue
<template> <DxLookup> <DxDropDownOptions :hide-on-outside-click="true" :show-title="false" /> </DxLookup> </template> <script> // ... import { DxLookup, DxDropDownOptions } from 'devextreme-vue/lookup'; export default { components: { DxLookup, DxDropDownOptions }, data() { return { // ... }; } } </script>
React
import { Lookup, DropDownOptions } from 'devextreme-react/lookup'; function App() { return ( <Lookup> <DropDownOptions hideOnOutsideClick={true} showTitle={false} /> </Lookup> ); } export default App;
You have configured basic Lookup features. For more information about this UI component and examples, refer to the following resources:
If you have technical questions, please create a support ticket in the DevExpress Support Center.