Directory

← Back

TokenField

A field for selecting multiple tokens/tags; a.k.a multi-select ComboBox

Author

Rating

Popularity

<100

A field that allows the user to select multiple 'tokens' using a ComboBox (which by default actually looks like a TextField w/ suggestions).

The field is very configurable, as can be seen in the demo.

Features include:

  • tokens can be inserted before/after input (over/under/etc depending on layout)
  • backspace/delete removes last token (customizeable)
  • layout can be changed
  • suggestions from container
  • auto add new to container
  • disallow tokens not in container
  • custom action on add (+ detect if token is in container)
  • custom configuring of the token button (style, caption, etc)
  • custom action on remove
  • built in style for either Token or ComboBox input look
  • built in styles for buttons, default and "emphasize"

Note that Vaadin 6.3.3 fixes some bugs in the ComboBox, which TokenField uses.

Sample code

                /*
                 * This is the most basic use case using all defaults; it's
                 * empty to begin with, the user can enter new tokens, 
                 * which are automatically added to the container
                 */


                TokenField f = new TokenField("Add tags");
                addComponent(f);

                TokenField f = new TokenField(lo) {
                    protected void onTokenInput(Object tokenId) {
                        // default adds the token
                    }

                    protected void onTokenClicked(final Object tokenId) {
                        // default removes w/o dialog
                    }

                    protected void configureTokenButton(Object tokenId,
                            Button button) {
                        // default sets  sets style & caption
                    }
                };
                f.setStyleName(TokenField.STYLE_TOKENFIELD); // remove fake textfield look
                f.setWidth("100%"); // width...
                f.setInputWidth("100%"); // and input width separately
                f.setContainerDataSource(tokens); // 'address book'
                f.setFilteringMode(ComboBox.FILTERINGMODE_CONTAINS); // suggest
                f.setTokenCaptionPropertyId("name"); // use container item property "name" in input
                f.setInputPrompt("Enter contact name or new email address");
                f.setRememberNewTokens(false); // we can opt to do this ourselves
{
                /*
                 * In this example, most features are exercised. A container
                 * with generated contacts is used. The input has filtering
                 * (a.k.a suggestions) enabled, and the added token button is
                 * configured so that it is in the standard "Name <email>"
                 * -format. New contacts can be added to the container ('address
                 * book'), or added as-is (in which case it's styled
                 * differently).
                 */

                Panel p = new Panel("Full featured example");
                p.getContent().setStyleName("black");
                addComponent(p);

                // generate container
                Container tokens = generateTestContainer();

                // we want this to be vertical
                VerticalLayout lo = new VerticalLayout();
                lo.setSpacing(true);

                final TokenField f = new TokenField(lo) {

                    private static final long serialVersionUID = 5530375996928514871L;

                    // dialog if not in 'address book', otherwise just add
                    protected void onTokenInput(Object tokenId) {
                        Set<Object> set = (Set<Object>) getValue();
                        Contact c = new Contact("", tokenId.toString());
                        if (set != null && set.contains(c)) {
                            // duplicate
                            getWindow().showNotification(
                                    getTokenCaption(tokenId)
                                            + " is already added");
                        } else {
                            if (!cb.containsId(c)) {
                                // don't add directly,
                                // show custom "add to address book" dialog
                                addWindow(new EditContactWindow(tokenId
                                        .toString(), this));
                            } else {
                                // it's in the 'address book', just add
                                addToken(tokenId);
                            }
                        }
                    }

                    // show confirm dialog
                    protected void onTokenClick(final Object tokenId) {
                        getWindow().addWindow(
                                new RemoveWindow((Contact) tokenId, this));
                    }

                    // just delete, no confirm
                    protected void onTokenDelete(Object tokenId) {
                        this.removeToken(tokenId);
                    }

                    // custom caption + style if not in 'address book'
                    protected void configureTokenButton(Object tokenId,
                            Button button) {
                        super.configureTokenButton(tokenId, button);
                        // custom caption
                        button.setCaption(getTokenCaption(tokenId) + " <"
                                + tokenId + ">");
                        // width
                        button.setWidth("100%");

                        if (!cb.containsId(tokenId)) {
                            // it's not in the address book; style
                            button
                                    .addStyleName(TokenField.STYLE_BUTTON_EMPHAZISED);
                        }
                    }
                };
                p.addComponent(f);
                // This would turn on the "fake tekstfield" look:
                f.setStyleName(TokenField.STYLE_TOKENFIELD);
                f.setWidth("100%");
                f.setInputWidth("100%");
                f.setContainerDataSource(tokens); // 'address book'
                f.setFilteringMode(ComboBox.FILTERINGMODE_CONTAINS); // suggest
                f.setTokenCaptionPropertyId("name"); // use name in input
                f.setInputPrompt("Enter contact name or new email address");
                f.setRememberNewTokens(false); // we'll do this via the dialog
                // Pre-add a few:
                Iterator it = f.getTokenIds().iterator();
                f.addToken(it.next());
                f.addToken(it.next());
                f.addToken(new Contact("", "thatnewguy@example.com"));
}

    /**
     * This is the window used to confirm removal
     */
    class RemoveWindow extends Window {

        private static final long serialVersionUID = -7140907025722511460L;

        RemoveWindow(final Contact c, final TokenField f) {
            super("Remove " + c.getName() + "?");

            setStyleName("black");
            setResizable(false);
            center();
            setModal(true);
            setWidth("250px");
            setClosable(false);

            // layout buttons horizontally
            HorizontalLayout hz = new HorizontalLayout();
            addComponent(hz);
            hz.setSpacing(true);
            hz.setWidth("100%");

            Button cancel = new Button("Cancel", new Button.ClickListener() {

                private static final long serialVersionUID = 7675170261217815011L;

                public void buttonClick(ClickEvent event) {
                    f.getWindow().removeWindow(getWindow());
                }
            });
            hz.addComponent(cancel);
            hz.setComponentAlignment(cancel, Alignment.MIDDLE_LEFT);

            Button remove = new Button("Remove", new Button.ClickListener() {

                private static final long serialVersionUID = 5004855711589989635L;

                public void buttonClick(ClickEvent event) {
                    f.removeToken(c);
                    f.getWindow().removeWindow(getWindow());
                }
            });
            hz.addComponent(remove);
            hz.setComponentAlignment(remove, Alignment.MIDDLE_RIGHT);

        }
    }

    /**
     * This is the window used to add new contacts to the 'address book'. It
     * does not do proper validation - you can add weird stuff.
     */
    class EditContactWindow extends Window {
        private Contact contact;

        EditContactWindow(final String t, final TokenField f) {
            super("New Contact");
            if (t.contains("@")) {
                contact = new Contact("", t);
            } else {
                contact = new Contact(t, "");
            }
            setModal(true);
            center();
            setWidth("250px");
            setStyleName("black");
            setResizable(false);

            // Just bind a Form to the Contact -pojo via BeanItem
            Form form = new Form();
            form.setItemDataSource(new BeanItem<Contact>(contact));
            form.setImmediate(true);
            addComponent(form);

            // layout buttons horizontally
            HorizontalLayout hz = new HorizontalLayout();
            addComponent(hz);
            hz.setSpacing(true);
            hz.setWidth("100%");

            Button dont = new Button("Don't add", new Button.ClickListener() {

                private static final long serialVersionUID = -1198191849568844582L;

                public void buttonClick(ClickEvent event) {
                    if (contact.getEmail() == null
                            || contact.getEmail().length() < 1) {
                        contact.setEmail(contact.getName());
                    }
                    f.addToken(contact);
                    f.getWindow().removeWindow(getWindow());
                }
            });
            hz.addComponent(dont);
            hz.setComponentAlignment(dont, Alignment.MIDDLE_LEFT);

            Button add = new Button("Add to contacts",
                    new Button.ClickListener() {

                        private static final long serialVersionUID = 1L;

                        public void buttonClick(ClickEvent event) {
                            if (contact.getEmail() == null
                                    || contact.getEmail().length() < 1) {
                                contact.setEmail(contact.getName());
                            }
                          

Compatibility

(Loading compatibility data...)

Was this helpful? Need more help?
Leave a comment or a question below. You can also join the chat on Discord or ask questions on StackOverflow.

Version

Released
2010-02-19
Maturity
STABLE
License
Apache License 2.0

Compatibility

Framework
Vaadin 6.0+
Vaadin 7.0+ in 7.0.0
Browser
Internet Explorer
Internet Explorer
Internet Explorer
Firefox
Opera
Safari

TokenField - Vaadin Add-on Directory

A field for selecting multiple tokens/tags; a.k.a multi-select ComboBox TokenField - Vaadin Add-on Directory
A field that allows the user to select multiple 'tokens' using a ComboBox (which by default actually looks like a TextField w/ suggestions). The field is very configurable, as can be seen in the demo. Features include: - tokens can be inserted before/after input (over/under/etc depending on layout) - backspace/delete removes last token (customizeable) - layout can be changed - suggestions from container - auto add new to container - disallow tokens not in container - custom action on add (+ detect if token is in container) - custom configuring of the token button (style, caption, etc) - custom action on remove - built in style for either Token or ComboBox input look - built in styles for buttons, default and "emphasize" Note that Vaadin 6.3.3 fixes some bugs in the ComboBox, which TokenField uses.
Online Demo
Issue Tracker
Source Code
Discussion Forum

TokenField version 0.1
null

TokenField version 0.8
null

TokenField version 0.9
null

TokenField version 1.0
null

TokenField version 7.0.0
Converted to work with Vaadin 7. Also added a possibility to customize the adding of new items to the dropdown.

TokenField version 7.0.1
Updated to work with 7.0 final. Note: CSS selectors made stronger, you might have to do the same if you have styled TokenField.

Online