Angular TagBox - Limit the Tag Count

Selected Tags

The following code shows the onValueChanged event handler's implementation that limits the number of tags a user can select in the TagBox:

jQuery
JavaScript
HTML
$(function(){
    const products = [
        "HD Video Player",
        "SuperHD Video Player",
        "SuperPlasma 50",
        "SuperLED 50",
        // ...
    ],
    maxItems = 2;

    $("#tagBoxContainer").dxTagBox({
        dataSource: products,
        onValueChanged: function(e) {
            if (e.value.length > maxItems) {
                const newValue = e.value.slice(0, maxItems); 
                e.component.option("value", newValue);
                tooltip.show();
            }
        }
    });

    const tooltip = $("#tooltipContainer").dxTooltip({
        target: "#tagBoxContainer",
        position:"bottom", 
        hideEvent: {
            name: "mouseout",
            delay: 2000
        }  
    }).dxTooltip("instance");
});
<div id="tagBoxContainer"></div>
<div id="tooltipContainer">Limit reached</div>
Angular
HTML
TypeScript
<dx-tag-box id="tagBoxContainer"
    [dataSource]="products"
    (onValueChanged)="onValueChanged($event)">
</dx-tag-box>
<dx-tooltip
    target="#tagBoxContainer"
    position="bottom"
    [hideEvent]="{ name: 'mouseout', delay: 2000 }"
    [(visible)]="isVisible">
    <div *dxTemplate="let data of 'content'">
        <p>Limit reached</p>
    </div>
</dx-tooltip>
import { DxTagBoxModule, DxTooltipModule } from "devextreme-angular";
// ...
export class AppComponent {
    isVisible: boolean = false;
    products = [
        "HD Video Player",
        "SuperHD Video Player",
        "SuperPlasma 50",
        "SuperLED 50",
        // ...
    ];
    maxItems: number = 2;
    onValueChanged (e) {
        if (e.value.length > this.maxItems) {
            let newValue = e.value.slice(0, this.maxItems); 
            e.component.option("value", newValue);
            this.isVisible = true;
        }
    }
}
@NgModule({
     imports: [
         // ...
         DxTagBoxModule,
         DxTooltipModule
     ],
     // ...
 })
Vue
<template>
    <div>
        <DxTagBox
            id="tagBoxContainer"
            :data-source="products"
            @value-changed="onValueChanged"
        />
        <DxTooltip 
            target="#tagBoxContainer"
            :hide-event="hideEvent"
            position="bottom"
            :visible="isTooltipVisible">
            <template>
                <p>Limit reached</p>
            </template>
        </DxTooltip>
    </div>
</template>

<script>
import 'devextreme/dist/css/dx.light.css';

import { DxTagBox } from 'devextreme-vue/tag-box';
import { DxTooltip } from 'devextreme-vue/tooltip';

export default {
    components: {
        DxTagBox,
        DxTooltip
    },
    data() {
        return {
            hideEvent: { name: 'mouseout', delay: 2000 },
            products: [
                "HD Video Player",
                "SuperHD Video Player",
                "SuperPlasma 50",
                "SuperLED 50",
                // ...
            ],
            isTooltipVisible: false,
            maxItems: 2
        };
    },
    methods: {
        onValueChanged(e) {
            if (e.value.length > this.maxItems) {
                const newValue = e.value.slice(0, this.maxItems);
                e.component.option('value', newValue);
                this.isTooltipVisible = true;
            }
        }
    }
}
</script>
React
import React from 'react';
import 'devextreme/dist/css/dx.light.css';

import { TagBox } from 'devextreme-react/tag-box';
import { Tooltip } from 'devextreme-react/tooltip';

const products = [
    "HD Video Player",
    "SuperHD Video Player",
    "SuperPlasma 50",
    "SuperLED 50",
    // ...
];

const renderContent = () => {
    return (
        <p>Limit reached</p>
    );
}

class App extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            isTooltipVisible: false
        }

        this.maxItems = 2;
        this.hideEvent = { delay: 2000, name: "mouseout" };

        this.onValueChanged = this.onValueChanged.bind(this);
        this.onTooltipHiding = this.onTooltipHiding.bind(this);
    }

    onValueChanged(e) {
        if (e.value.length > this.maxItems) {
            const newValue = e.value.slice(0, this.maxItems);
            e.component.option('value', newValue);
            this.setState({
                isTooltipVisible: true
            });
        }
    }

    onTooltipHiding(e) {
        this.setState({
            isTooltipVisible: false
        });
    }

    render() {
        return (
            <div>
                <TagBox
                    id="tagBoxContainer"
                    dataSource={products}
                    onValueChanged={this.onValueChanged}
                />
                <Tooltip
                    target="#tagBoxContainer"
                    hideEvent={this.hideEvent}
                    contentRender={renderContent}
                    position="bottom"
                    visible={this.state.isTooltipVisible}
                    onHiding={this.onTooltipHiding}
                />
            </div>
        );
    }
}

export default App;

Displayed Tags

Specify the maxDisplayedTags property to limit the number of displayed tags. In this case, when the specified limit is exceeded, the UI component replaces tags with a single multi-tag displaying the number of selected items. The TagBox can display the multi-tag alone or with ordinary tags depending on the showMultiTagOnly property's value.

jQuery
JavaScript
$(function(){
    const products = [
        "HD Video Player",
        "SuperHD Video Player",
        "SuperPlasma 50",
        "SuperLED 50",
        // ...
    ];

    $("#tagBoxContainer").dxTagBox({
        dataSource: products,
        maxDisplayedTags: 3,
        showMultiTagOnly: false
    });
});
Angular
HTML
TypeScript
<dx-tag-box
    [dataSource]="products"
    [maxDisplayedTags]="3"
    [showMultiTagOnly]="false">
</dx-tag-box>
import { DxTagBoxModule } from "devextreme-angular";
// ...
export class AppComponent {
    products = [
        "HD Video Player",
        "SuperHD Video Player",
        "SuperPlasma 50",
        "SuperLED 50",
        // ...
    ];
}
@NgModule({
     imports: [
         // ...
         DxTagBoxModule
     ],
     // ...
 })
Vue
<template>
    <DxTagBox
        :data-source="products"
        :max-displayed-tags="3"
        :show-multi-tag-only="false"
    />
</template>

<script>
import 'devextreme/dist/css/dx.light.css';

import { DxTagBox } from 'devextreme-vue/tag-box';

export default {
    components: {
        DxTagBox
    },
    data() {
        return {
            products: [
                'HD Video Player',
                'SuperHD Video Player',
                'SuperPlasma 50',
                'SuperLED 50',
                // ...
            ]
        };
    }
}
</script>
React
import React from 'react';
import 'devextreme/dist/css/dx.light.css';

import { TagBox } from 'devextreme-react/tag-box';

const products = [
    'HD Video Player',
    'SuperHD Video Player',
    'SuperPlasma 50',
    'SuperLED 50',
    // ...
];

class App extends React.Component {
    render() {
        return (
            <TagBox
                dataSource={products}
                maxDisplayedTags={3}
                showMultiTagOnly={false}
            />
        );
    }
}

export default App;

You can also customize the multi-tag within the onMultiTagPreparing event handler. In the following code, the multi-tag's text is changed and it is shown only when a user selects all items:

jQuery
JavaScript
$(function(){
    $("#tagBoxContainer").dxTagBox({
        dataSource: products,
        maxDisplayedTags: 2,
        onMultiTagPreparing: function (args) {
            const selectedItemsLength = args.selectedItems.length;
            const totalCount = products.length;
            if (selectedItemsLength < totalCount) {
                args.cancel = true;
            } else {
                args.text = "All selected (" + selectedItemsLength + ")";
                args.multiTagElement.addClass("red");
            }
        }
    });
});
Angular
HTML
TypeScript
<dx-tag-box
    [dataSource]="products"
    [maxDisplayedTags]="2"
    (onMultiTagPreparing)="onMultiTagPreparing($event)">
</dx-tag-box>
import { DxTagBoxModule } from "devextreme-angular";
// ...
export class AppComponent {
    products = [
        "HD Video Player",
        "SuperHD Video Player",
        "SuperPlasma 50",
        "SuperLED 50",
        // ...
    ];
    onMultiTagPreparing (e) {
        const selectedItemsLength = e.selectedItems.length;
        const totalCount = this.products.length;
        if (selectedItemsLength < totalCount) {
            e.cancel = true;
        } else {
            e.text = "All selected (" + selectedItemsLength + ")";
            e.multiTagElement.classList.add("red");
        }
    }
}
@NgModule({
     imports: [
         // ...
         DxTagBoxModule
     ],
     // ...
 })
Vue
<template>
    <DxTagBox
        :data-source="products"
        :max-displayed-tags="2"
        @multi-tag-preparing="onMultiTagPreparing"
    />
</template>

<script>
import 'devextreme/dist/css/dx.light.css';

import { DxTagBox } from 'devextreme-vue/tag-box';

export default {
    components: {
        DxTagBox
    },
    data() {
        return {
            products: [
                'HD Video Player',
                'SuperHD Video Player',
                'SuperPlasma 50',
                'SuperLED 50',
                // ...
            ]
        };
    },
    methods: {
        onMultiTagPreparing(args) {
            const selectedItemsLength = args.selectedItems.length;
            const totalCount = this.products.length;
            if (selectedItemsLength < totalCount) {
                args.cancel = true;
            } else {
                args.text = 'All selected (' + selectedItemsLength + ')';
                args.multiTagElement.classList.add('red');
            }
        }
    }
}
</script>
React
import React from 'react';
import 'devextreme/dist/css/dx.light.css';

import { TagBox } from 'devextreme-react/tag-box';

const products = [
    'HD Video Player',
    'SuperHD Video Player',
    'SuperPlasma 50',
    'SuperLED 50',
    // ...
];

class App extends React.Component {
    render() {
        return (
            <TagBox
                dataSource={products}
                maxDisplayedTags={2}
                onMultiTagPreparing={this.onMultiTagPreparing}
            />
        );
    }

    onMultiTagPreparing(args) {
        const selectedItemsLength = args.selectedItems.length;
        const totalCount = products.length;
        if (selectedItemsLength < totalCount) {
            args.cancel = true;
        } else {
            args.text = 'All selected (' + selectedItemsLength + ')';
            args.multiTagElement.classList.add('red');
        }
    }
}

export default App;

View Demo