The USD/EUR rate is taken from www.wikipedia.org and is relevant on 14 April 2021
Feel free to share demo-related thoughts here.
If you have technical questions, please create a support ticket in the DevExpress Support Center.
Thank you for the feedback!
If you have technical questions, please create a support ticket in the DevExpress Support Center.
Backend API
import React, { useCallback, useMemo, useState } from 'react';
import { TextBox, Button as TextBoxButton, TextBoxTypes } from 'devextreme-react/text-box';
import { NumberBox, Button as NumberBoxButton, NumberBoxTypes } from 'devextreme-react/number-box';
import { DateBox, Button as DateBoxButton, DateBoxTypes } from 'devextreme-react/date-box';
import { ButtonTypes } from 'devextreme-react/button';
const millisecondsInDay = 24 * 60 * 60 * 1000;
const currencyLabel = { 'aria-label': 'Multi Currency' };
const dateBoxLabel = { 'aria-label': 'Date' };
const passwordLabel = { 'aria-label': 'Password' };
function App() {
const [passwordMode, setPasswordMode] = useState<TextBoxTypes.TextBoxType>('password');
const [currencyFormat, setCurrencyFormat] = useState('$ #.##');
const [currencyValue, setCurrencyValue] = useState(14500.55);
const [dateValue, setDateValue] = useState(new Date().getTime());
const passwordButton = useMemo<ButtonTypes.Properties>(
() => ({
icon: 'eyeopen',
stylingMode: 'text',
onClick: () => {
setPasswordMode((prevPasswordMode: string) =>
(prevPasswordMode === 'text' ? 'password' : 'text'));
},
}),
[setPasswordMode],
);
const currencyButton = useMemo<ButtonTypes.Properties>(
() => ({
text: '€',
stylingMode: 'text',
width: 32,
elementAttr: {
class: 'currency',
},
onClick: (e) => {
if (e.component.option('text') === '$') {
e.component.option('text', '€');
setCurrencyFormat('$ #.##');
setCurrencyValue((prevCurrencyValue: number) => prevCurrencyValue / 0.836);
} else {
e.component.option('text', '$');
setCurrencyFormat('€ #.##');
setCurrencyValue((prevCurrencyValue: number) => prevCurrencyValue * 0.836);
}
},
}),
[setCurrencyFormat, setCurrencyValue],
);
const todayButton = useMemo<ButtonTypes.Properties>(
() => ({
text: 'Today',
stylingMode: 'text',
onClick: () => {
setDateValue(new Date().getTime());
},
}),
[setDateValue],
);
const prevDateButton = useMemo<ButtonTypes.Properties>(
() => ({
icon: 'spinprev',
stylingMode: 'text',
onClick: () => {
setDateValue((prevDateValue: number) => prevDateValue - millisecondsInDay);
},
}),
[setDateValue],
);
const nextDateButton = useMemo<ButtonTypes.Properties>(
() => ({
icon: 'spinnext',
stylingMode: 'text',
onClick: () => {
setDateValue((prevDateValue: number) => prevDateValue + millisecondsInDay);
},
}),
[setDateValue],
);
const onDateChanged = useCallback(
(e: DateBoxTypes.ValueChangedEvent) => {
setDateValue(e.value);
},
[setDateValue],
);
const changeCurrency = useCallback(
(data: NumberBoxTypes.ValueChangedEvent) => {
setCurrencyValue(data.value);
},
[setCurrencyValue],
);
return (
<React.Fragment>
<div className="dx-fieldset">
<div className="dx-field">
<div className="dx-field-label">Password TextBox</div>
<div className="dx-field-value">
<TextBox
placeholder="password"
stylingMode="filled"
defaultValue="password"
inputAttr={passwordLabel}
mode={passwordMode}
>
<TextBoxButton
name="password"
location="after"
options={passwordButton}
/>
</TextBox>
</div>
</div>
<div className="dx-field">
<div className="dx-field-label">Multi-currency NumberBox</div>
<div className="dx-field-value">
<NumberBox
showClearButton={true}
showSpinButtons={true}
format={currencyFormat}
value={currencyValue}
inputAttr={currencyLabel}
onValueChanged={changeCurrency}
>
<NumberBoxButton
name="currency"
location="after"
options={currencyButton}
/>
<NumberBoxButton name="clear" />
<NumberBoxButton name="spins" />
</NumberBox>
</div>
</div>
<div className="dx-field">
<div className="dx-field-label">Advanced DateBox</div>
<div className="dx-field-value">
<DateBox
value={dateValue}
stylingMode="outlined"
inputAttr={dateBoxLabel}
onValueChanged={onDateChanged}
>
<DateBoxButton
name="today"
location="before"
options={todayButton}
/>
<DateBoxButton
name="prevDate"
location="before"
options={prevDateButton}
/>
<DateBoxButton
name="nextDate"
location="after"
options={nextDateButton}
/>
<DateBoxButton name="dropDown" />
</DateBox>
</div>
</div>
</div>
</React.Fragment>
);
}
export default App;
import React, { useCallback, useMemo, useState } from 'react';
import { TextBox, Button as TextBoxButton } from 'devextreme-react/text-box';
import { NumberBox, Button as NumberBoxButton } from 'devextreme-react/number-box';
import { DateBox, Button as DateBoxButton } from 'devextreme-react/date-box';
const millisecondsInDay = 24 * 60 * 60 * 1000;
const currencyLabel = { 'aria-label': 'Multi Currency' };
const dateBoxLabel = { 'aria-label': 'Date' };
const passwordLabel = { 'aria-label': 'Password' };
function App() {
const [passwordMode, setPasswordMode] = useState('password');
const [currencyFormat, setCurrencyFormat] = useState('$ #.##');
const [currencyValue, setCurrencyValue] = useState(14500.55);
const [dateValue, setDateValue] = useState(new Date().getTime());
const passwordButton = useMemo(
() => ({
icon: 'eyeopen',
stylingMode: 'text',
onClick: () => {
setPasswordMode((prevPasswordMode) => (prevPasswordMode === 'text' ? 'password' : 'text'));
},
}),
[setPasswordMode],
);
const currencyButton = useMemo(
() => ({
text: '€',
stylingMode: 'text',
width: 32,
elementAttr: {
class: 'currency',
},
onClick: (e) => {
if (e.component.option('text') === '$') {
e.component.option('text', '€');
setCurrencyFormat('$ #.##');
setCurrencyValue((prevCurrencyValue) => prevCurrencyValue / 0.836);
} else {
e.component.option('text', '$');
setCurrencyFormat('€ #.##');
setCurrencyValue((prevCurrencyValue) => prevCurrencyValue * 0.836);
}
},
}),
[setCurrencyFormat, setCurrencyValue],
);
const todayButton = useMemo(
() => ({
text: 'Today',
stylingMode: 'text',
onClick: () => {
setDateValue(new Date().getTime());
},
}),
[setDateValue],
);
const prevDateButton = useMemo(
() => ({
icon: 'spinprev',
stylingMode: 'text',
onClick: () => {
setDateValue((prevDateValue) => prevDateValue - millisecondsInDay);
},
}),
[setDateValue],
);
const nextDateButton = useMemo(
() => ({
icon: 'spinnext',
stylingMode: 'text',
onClick: () => {
setDateValue((prevDateValue) => prevDateValue + millisecondsInDay);
},
}),
[setDateValue],
);
const onDateChanged = useCallback(
(e) => {
setDateValue(e.value);
},
[setDateValue],
);
const changeCurrency = useCallback(
(data) => {
setCurrencyValue(data.value);
},
[setCurrencyValue],
);
return (
<React.Fragment>
<div className="dx-fieldset">
<div className="dx-field">
<div className="dx-field-label">Password TextBox</div>
<div className="dx-field-value">
<TextBox
placeholder="password"
stylingMode="filled"
defaultValue="password"
inputAttr={passwordLabel}
mode={passwordMode}
>
<TextBoxButton
name="password"
location="after"
options={passwordButton}
/>
</TextBox>
</div>
</div>
<div className="dx-field">
<div className="dx-field-label">Multi-currency NumberBox</div>
<div className="dx-field-value">
<NumberBox
showClearButton={true}
showSpinButtons={true}
format={currencyFormat}
value={currencyValue}
inputAttr={currencyLabel}
onValueChanged={changeCurrency}
>
<NumberBoxButton
name="currency"
location="after"
options={currencyButton}
/>
<NumberBoxButton name="clear" />
<NumberBoxButton name="spins" />
</NumberBox>
</div>
</div>
<div className="dx-field">
<div className="dx-field-label">Advanced DateBox</div>
<div className="dx-field-value">
<DateBox
value={dateValue}
stylingMode="outlined"
inputAttr={dateBoxLabel}
onValueChanged={onDateChanged}
>
<DateBoxButton
name="today"
location="before"
options={todayButton}
/>
<DateBoxButton
name="prevDate"
location="before"
options={prevDateButton}
/>
<DateBoxButton
name="nextDate"
location="after"
options={nextDateButton}
/>
<DateBoxButton name="dropDown" />
</DateBox>
</div>
</div>
</div>
</React.Fragment>
);
}
export default App;
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App.tsx';
ReactDOM.render(<App />, document.getElementById('app'));
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',
'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);
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App.js';
ReactDOM.render(<App />, document.getElementById('app'));
<!DOCTYPE html>
<html lang="en">
<head>
<title>DevExtreme Demo</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0" />
<link rel="stylesheet" type="text/css" href="https://cdn3.devexpress.com/jslib/24.2.3/css/dx.light.css" />
<link rel="stylesheet" type="text/css" href="styles.css" />
<script src="https://unpkg.com/core-js@2.6.12/client/shim.min.js"></script>
<script src="https://unpkg.com/systemjs@0.21.3/dist/system.js"></script>
<script type="text/javascript" src="config.js"></script>
<script type="text/javascript">
System.import("./index.tsx");
</script>
</head>
<body class="dx-viewport">
<div class="demo-container">
<div id="app"></div>
</div>
</body>
</html>
.dx-fieldset {
min-height: 560px;
width: 560px;
margin: 0 auto;
}
.currency {
min-width: 32px;
}
.dx-button.currency .dx-button-content {
font-size: 120%;
padding-left: 5px;
padding-right: 5px;
}
Each object in the buttons[] array should have the name field—the button's identifier. In addition, specify the button's location relative to the input text field and options of the Button component used as the action button.
The buttons[] array also accepts string values—the names of built-in buttons. Declare them in the order the buttons should have in the component. String and object declarations can be used in the same array.