If you have technical questions, please create a support ticket in the DevExpress Support Center.
import React, { useCallback, useState } from 'react';
import ODataStore from 'devextreme/data/odata/store';
import { Autocomplete, AutocompleteTypes } from 'devextreme-react/autocomplete';
import CustomStore from 'devextreme/data/custom_store';
import 'whatwg-fetch';
import { names, surnames, positions } from './data.ts';
function isNotEmpty(value: string) {
return value !== undefined && value !== null && value !== '';
}
const positionLabel = { 'aria-label': 'Position' };
const position = positions[0];
const states = new ODataStore({
version: 2,
url: 'https://js.devexpress.com/Demos/DevAV/odata/States?$select=Sate_ID,State_Long,State_Short',
key: 'Sate_ID',
keyType: 'Int32',
});
const clientsStore = new CustomStore({
key: 'Value',
useDefaultSearch: true,
load: (loadOptions) => {
let params = '?';
['skip', 'take', 'filter'].forEach((option) => {
if (option in loadOptions && isNotEmpty(loadOptions[option])) {
params += `${option}=${JSON.stringify(loadOptions[option])}&`;
}
});
params = params.slice(0, -1);
return fetch(`https://js.devexpress.com/Demos/Mvc/api/DataGridWebApi/CustomersLookup${params}`)
.then((response) => response.json())
.then((data) => ({
data: data.data,
}))
.catch(() => {
throw new Error('Data Loading Error');
});
},
});
const renderState = (data) => (
<span>
{data.State_Long} ({data.State_Short})
</span>
);
function App() {
const [firstName, setFirstName] = useState('');
const [lastName, setLastName] = useState('');
const [state, setState] = useState('');
const [currentClient, setCurrentClient] = useState('');
const handleFirstNameChange = useCallback((e: AutocompleteTypes.ValueChangedEvent) => {
setFirstName(e.value);
}, []);
const handleLastNameChange = useCallback((e: AutocompleteTypes.ValueChangedEvent) => {
setLastName(e.value);
}, []);
const handleStateChange = useCallback((e: AutocompleteTypes.ValueChangedEvent) => {
setState(e.value);
}, []);
const handleCurrentClientChange = useCallback((e: AutocompleteTypes.ValueChangedEvent) => {
setCurrentClient(e.value);
}, []);
let fullInfo = '';
fullInfo += `${firstName || ''} ${lastName || ''}`.trim();
fullInfo += fullInfo && position ? `, ${position}` : position || '';
fullInfo += fullInfo && state ? `, ${state}` : state || '';
fullInfo += fullInfo && currentClient ? `, ${currentClient}` : currentClient || '';
return (
<div className="form">
<div className="dx-fieldset">
<div className="dx-fieldset-header">Default Mode</div>
<div className="dx-field">
<div className="dx-field-label">First Name</div>
<div className="dx-field-value">
<Autocomplete
dataSource={names}
value={firstName}
onValueChanged={handleFirstNameChange}
placeholder="Type first name..."
/>
</div>
</div>
</div>
<div className="dx-fieldset">
<div className="dx-fieldset-header">With Clear Button</div>
<div className="dx-field">
<div className="dx-field-label">Last Name</div>
<div className="dx-field-value">
<Autocomplete
dataSource={surnames}
value={lastName}
onValueChanged={handleLastNameChange}
showClearButton={true}
placeholder="Type last name..."
/>
</div>
</div>
</div>
<div className="dx-fieldset">
<div className="dx-fieldset-header">Disabled</div>
<div className="dx-field">
<div className="dx-field-label">Position</div>
<div className="dx-field-value">
<Autocomplete
dataSource={positions}
value={position}
disabled={true}
inputAttr={positionLabel}
/>
</div>
</div>
</div>
<div className="dx-fieldset">
<div className="dx-fieldset-header">Custom Item Template and Data Source Usage</div>
<div className="dx-field">
<div className="dx-field-label">State</div>
<div className="dx-field-value">
<Autocomplete
dataSource={states}
value={state}
valueExpr="State_Long"
onValueChanged={handleStateChange}
placeholder="Type state name..."
itemRender={renderState}
/>
</div>
</div>
</div>
<div className="dx-fieldset">
<div className="dx-fieldset-header">Custom Store and Search Options</div>
<div className="dx-field">
<div className="dx-field-label">Current Client</div>
<div className="dx-field-value">
<Autocomplete
dataSource={clientsStore}
value={currentClient}
valueExpr="Text"
onValueChanged={handleCurrentClientChange}
minSearchLength={2}
searchTimeout={500}
placeholder="Type client name..."
/>
</div>
</div>
</div>
<div className="dx-fieldset">
<div className="dx-fieldset-header">Event Handling</div>
<div className="employees-data">
Employee data: <span>{fullInfo}</span>
</div>
</div>
</div>
);
}
export default App;
xxxxxxxxxx
import React, { useCallback, useState } from 'react';
import ODataStore from 'devextreme/data/odata/store';
import { Autocomplete } from 'devextreme-react/autocomplete';
import CustomStore from 'devextreme/data/custom_store';
import 'whatwg-fetch';
import { names, surnames, positions } from './data.js';
function isNotEmpty(value) {
return value !== undefined && value !== null && value !== '';
}
const positionLabel = { 'aria-label': 'Position' };
const position = positions[0];
const states = new ODataStore({
version: 2,
url: 'https://js.devexpress.com/Demos/DevAV/odata/States?$select=Sate_ID,State_Long,State_Short',
key: 'Sate_ID',
keyType: 'Int32',
});
const clientsStore = new CustomStore({
key: 'Value',
useDefaultSearch: true,
load: (loadOptions) => {
let params = '?';
['skip', 'take', 'filter'].forEach((option) => {
if (option in loadOptions && isNotEmpty(loadOptions[option])) {
params += `${option}=${JSON.stringify(loadOptions[option])}&`;
}
});
params = params.slice(0, -1);
return fetch(`https://js.devexpress.com/Demos/Mvc/api/DataGridWebApi/CustomersLookup${params}`)
.then((response) => response.json())
.then((data) => ({
data: data.data,
}))
.catch(() => {
throw new Error('Data Loading Error');
});
},
});
const renderState = (data) => (
<span>
{data.State_Long} ({data.State_Short})
</span>
);
function App() {
const [firstName, setFirstName] = useState('');
const [lastName, setLastName] = useState('');
const [state, setState] = useState('');
const [currentClient, setCurrentClient] = useState('');
const handleFirstNameChange = useCallback((e) => {
setFirstName(e.value);
}, []);
const handleLastNameChange = useCallback((e) => {
setLastName(e.value);
}, []);
const handleStateChange = useCallback((e) => {
setState(e.value);
}, []);
const handleCurrentClientChange = useCallback((e) => {
setCurrentClient(e.value);
}, []);
let fullInfo = '';
fullInfo += `${firstName || ''} ${lastName || ''}`.trim();
fullInfo += fullInfo && position ? `, ${position}` : position || '';
fullInfo += fullInfo && state ? `, ${state}` : state || '';
fullInfo += fullInfo && currentClient ? `, ${currentClient}` : currentClient || '';
return (
<div className="form">
<div className="dx-fieldset">
<div className="dx-fieldset-header">Default Mode</div>
<div className="dx-field">
<div className="dx-field-label">First Name</div>
<div className="dx-field-value">
<Autocomplete
dataSource={names}
value={firstName}
onValueChanged={handleFirstNameChange}
placeholder="Type first name..."
/>
</div>
</div>
</div>
<div className="dx-fieldset">
<div className="dx-fieldset-header">With Clear Button</div>
<div className="dx-field">
<div className="dx-field-label">Last Name</div>
<div className="dx-field-value">
<Autocomplete
dataSource={surnames}
value={lastName}
onValueChanged={handleLastNameChange}
showClearButton={true}
placeholder="Type last name..."
/>
</div>
</div>
</div>
<div className="dx-fieldset">
<div className="dx-fieldset-header">Disabled</div>
<div className="dx-field">
<div className="dx-field-label">Position</div>
<div className="dx-field-value">
<Autocomplete
dataSource={positions}
value={position}
disabled={true}
inputAttr={positionLabel}
/>
</div>
</div>
</div>
<div className="dx-fieldset">
<div className="dx-fieldset-header">Custom Item Template and Data Source Usage</div>
<div className="dx-field">
<div className="dx-field-label">State</div>
<div className="dx-field-value">
<Autocomplete
dataSource={states}
value={state}
valueExpr="State_Long"
onValueChanged={handleStateChange}
placeholder="Type state name..."
itemRender={renderState}
/>
</div>
</div>
</div>
<div className="dx-fieldset">
<div className="dx-fieldset-header">Custom Store and Search Options</div>
<div className="dx-field">
<div className="dx-field-label">Current Client</div>
<div className="dx-field-value">
<Autocomplete
dataSource={clientsStore}
value={currentClient}
valueExpr="Text"
onValueChanged={handleCurrentClientChange}
minSearchLength={2}
searchTimeout={500}
placeholder="Type client name..."
/>
</div>
</div>
</div>
<div className="dx-fieldset">
<div className="dx-fieldset-header">Event Handling</div>
<div className="employees-data">
Employee data: <span>{fullInfo}</span>
</div>
</div>
</div>
);
}
export default App;
xxxxxxxxxx
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App.tsx';
ReactDOM.render(<App />, document.getElementById('app'));
xxxxxxxxxx
export const names = ['James', 'John', 'Robert', 'Michael', 'William', 'David', 'Richard', 'Charles', 'Joseph', 'Thomas', 'Christopher', 'Daniel', 'Paul', 'Mark', 'Donald', 'George', 'Kenneth', 'Steven', 'Edward', 'Brian', 'Ronald', 'Anthony', 'Kevin', 'Jason', 'Jeff', 'Mary', 'Patricia', 'Linda', 'Barbara', 'Elizabeth', 'Jennifer', 'Maria', 'Susan', 'Margaret', 'Dorothy', 'Lisa', 'Nancy', 'Karen', 'Betty', 'Helen', 'Sandra', 'Donna', 'Carol', 'Ruth', 'Sharon', 'Michelle', 'Laura', 'Sarah', 'Kimberly', 'Deborah'];
export const surnames = ['Anderson', 'Smith', 'Johnson', 'Williams', 'Jones', 'Brown', 'Davis', 'Miller', 'Wilson', 'Moore', 'Taylor', 'Thomas', 'Jackson', 'White', 'Harris', 'Martin', 'Thompson', 'Garcia', 'Martinez', 'Robinson', 'Clark', 'Rodriguez', 'Lewis', 'Lee',
'Walker', 'Hall', 'Allen', 'Young', 'Hernandez', 'King', 'Wright', 'Lopez', 'Hill', 'Scott', 'Green', 'Adams', 'Baker', 'Gonzalez', 'Nelson', 'Carter', 'Mitchell', 'Perez', 'Roberts', 'Turner', 'Phillips', 'Campbell',
'Parker', 'Evans', 'Edwards', 'Collins',
];
export const positions = ['CEO', 'COO', 'CTO', 'CMO', 'HR Manager', 'IT Manager', 'Controller', 'Sales Manager', 'Support Manager'];
xxxxxxxxxx
window.exports = window.exports || {};
window.config = {
transpiler: 'ts',
typescriptOptions: {
module: 'system',
emitDecoratorMetadata: true,
experimentalDecorators: true,
jsx: 'react',
},
meta: {
'react': {
'esModule': true,
},
'typescript': {
'exports': 'ts',
},
'devextreme/time_zone_utils.js': {
'esModule': true,
},
'devextreme/localization.js': {
'esModule': true,
},
'devextreme/viz/palette.js': {
'esModule': true,
},
'openai': {
'esModule': true,
},
},
paths: {
'npm:': 'https://unpkg.com/',
'bundles:': 'bundles/',
'externals:': 'bundles/externals/',
},
defaultExtension: 'js',
map: {
'ts': 'npm:plugin-typescript@8.0.0/lib/plugin.js',
'typescript': 'npm:typescript@4.2.4/lib/typescript.js',
'jszip': 'npm:jszip@3.10.1/dist/jszip.min.js',
'react': 'npm:react@17.0.2/umd/react.development.js',
'react-dom': 'npm:react-dom@17.0.2/umd/react-dom.development.js',
'prop-types': 'npm:prop-types/prop-types.js',
'whatwg-fetch': 'npm:whatwg-fetch@2.0.4/fetch.js',
'rrule': 'npm:rrule@2.6.4/dist/es5/rrule.js',
'luxon': 'npm:luxon@3.4.4/build/global/luxon.min.js',
'es6-object-assign': 'npm:es6-object-assign',
'devextreme': 'npm:devextreme@link:../../packages/devextreme/artifacts/npm/devextreme/cjs',
'devextreme-react': 'npm:devextreme-react@link:../../packages/devextreme-react/npm/cjs',
'devextreme-quill': 'npm:devextreme-quill@1.7.1/dist/dx-quill.min.js',
'devexpress-diagram': 'npm:devexpress-diagram@2.2.5/dist/dx-diagram.js',
'devexpress-gantt': 'npm:devexpress-gantt@4.1.54/dist/dx-gantt.js',
'@devextreme/runtime': 'npm:@devextreme/runtime@3.0.12',
'inferno': 'npm:inferno@7.4.11/dist/inferno.min.js',
'inferno-compat': 'npm:inferno-compat/dist/inferno-compat.min.js',
'inferno-create-element': 'npm:inferno-create-element@7.4.11/dist/inferno-create-element.min.js',
'inferno-dom': 'npm:inferno-dom/dist/inferno-dom.min.js',
'inferno-hydrate': 'npm:inferno-hydrate/dist/inferno-hydrate.min.js',
'inferno-clone-vnode': 'npm:inferno-clone-vnode/dist/inferno-clone-vnode.min.js',
'inferno-create-class': 'npm:inferno-create-class/dist/inferno-create-class.min.js',
'inferno-extras': 'npm:inferno-extras/dist/inferno-extras.min.js',
'devextreme-cldr-data': 'npm:devextreme-cldr-data@1.0.3',
// SystemJS plugins
'plugin-babel': 'npm:systemjs-plugin-babel@0.0.25/plugin-babel.js',
'systemjs-babel-build': 'npm:systemjs-plugin-babel@0.0.25/systemjs-babel-browser.js',
// Prettier
'prettier/standalone': 'npm:prettier@2.8.8/standalone.js',
'prettier/parser-html': 'npm:prettier@2.8.8/parser-html.js',
},
packages: {
'devextreme': {
defaultExtension: 'js',
},
'devextreme-react': {
main: 'index.js',
},
'devextreme/events/utils': {
main: 'index',
},
'devextreme/localization/messages': {
format: 'json',
defaultExtension: 'json',
},
'devextreme/events': {
main: 'index',
},
'es6-object-assign': {
main: './index.js',
defaultExtension: 'js',
},
},
packageConfigPaths: [
'npm:@devextreme/*/package.json',
'npm:@devextreme/runtime@3.0.12/inferno/package.json',
],
babelOptions: {
sourceMaps: false,
stage0: true,
react: true,
},
};
System.config(window.config);
xxxxxxxxxx
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App.js';
ReactDOM.render(<App />, document.getElementById('app'));
xxxxxxxxxx
export const names = [
'James',
'John',
'Robert',
'Michael',
'William',
'David',
'Richard',
'Charles',
'Joseph',
'Thomas',
'Christopher',
'Daniel',
'Paul',
'Mark',
'Donald',
'George',
'Kenneth',
'Steven',
'Edward',
'Brian',
'Ronald',
'Anthony',
'Kevin',
'Jason',
'Jeff',
'Mary',
'Patricia',
'Linda',
'Barbara',
'Elizabeth',
'Jennifer',
'Maria',
'Susan',
'Margaret',
'Dorothy',
'Lisa',
'Nancy',
'Karen',
'Betty',
'Helen',
'Sandra',
'Donna',
'Carol',
'Ruth',
'Sharon',
'Michelle',
'Laura',
'Sarah',
'Kimberly',
'Deborah',
];
export const surnames = [
'Anderson',
'Smith',
'Johnson',
'Williams',
'Jones',
'Brown',
'Davis',
'Miller',
'Wilson',
'Moore',
'Taylor',
'Thomas',
'Jackson',
'White',
'Harris',
'Martin',
'Thompson',
'Garcia',
'Martinez',
'Robinson',
'Clark',
'Rodriguez',
'Lewis',
'Lee',
'Walker',
'Hall',
'Allen',
'Young',
'Hernandez',
'King',
'Wright',
'Lopez',
'Hill',
'Scott',
'Green',
'Adams',
'Baker',
'Gonzalez',
'Nelson',
'Carter',
'Mitchell',
'Perez',
'Roberts',
'Turner',
'Phillips',
'Campbell',
'Parker',
'Evans',
'Edwards',
'Collins',
];
export const positions = [
'CEO',
'COO',
'CTO',
'CMO',
'HR Manager',
'IT Manager',
'Controller',
'Sales Manager',
'Support Manager',
];
xxxxxxxxxx
<html lang="en">
<head></head>
<body class="dx-viewport">
<div class="demo-container">
<div id="app"></div>
</div>
</body>
</html>
xxxxxxxxxx
.employees-data {
padding-top: 16px;
padding-bottom: 10px;
}
Bind Autocomplete to Data
Use one of the following properties to supply data to the component:
-
items[]
Accepts a local data array. -
dataSource
Accepts a local data array, DataSource object, or DevExtreme data store. In this demo, every Autocomplete component is bound to a local array, except the following components:-
"Custom Item Template and Data Source Usage"
Uses an ODataStore. -
"Custom Store and Search Options"
Uses a CustomStore.
-
The value property stores the selected item. You can use the same property to select an item programmatically, as shown in the "Disabled" Autocomplete component.
If the data source contains objects, you should specify the valueExpr property. It accepts a data field name that uniquely identifies each data object. In this demo, valueExpr is specified only for the "Custom Item Template and Data Source Usage" and "Custom Store and Search Options" components because other components are bound to arrays of primitive values.
Configure Search Parameters
When a user types the first character, Autocomplete displays suggestions. To increase the number of characters that triggers suggestions, use the minSearchLength property. You can also specify the time interval Autocomplete should wait before it displays suggestions. Assign this time interval in milliseconds to the searchTimeout property. See the "Custom Store and Search Options" Autocomplete component for an example.
In most cases, the data field that supplies Autocomplete with suggestions is the same data field that is used to search for the entered text. If you use two different fields, assign the field that supplies Autocomplete with suggestions to the valueExpr property and the field used to search to the searchExpr property. Note that searchExpr also accepts arrays if you want to search multiple fields.
Handle Value Change
To handle value changes, implement the onValueChanged function. In this demo, we use onValueChanged to display the values of all Autocomplete components.
Appearance Customization
You can specify the following properties to customize the Autocomplete component's appearance:
-
placeholder
The text that is displayed when Autocomplete is empty. -
showClearButton
Adds a Clear button that empties the Autocomplete value as shown in the "With Clear Button" Autocomplete component. -
disabled
Disables the component. -
itemTemplate
Customizes the appearance of the Autocomplete suggestions. See the "Custom Item Template and Data Source Usage" component for an example.