My TokenField component is nearing 1.0, so I thought it’s time for some feedback - bring it on!
TokenField is technically a multiselect ComboBox that can be configured extensively. But I think it’s best not to try to explain too much with words, see the screenshots, video, or online demo instead:
Not a lot of feedback here, but TokenField still reached 1.0, with a lot of subtle and not-so-subtle improvements.
It’s re-styled, CssLayout is the default and works very well, focus stays in place, and backspace/del deletes tokens - those are the main things I can think of right now.
Feature list:
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”
Check out the new & improved
YouTube video for an overview.
In the
online demo , the black example has almost everything customized - confirm dialogs etc. Play with it! (Note: it’s trying to showoff the features, not be the most usable email entry there is…)
TokenField implements the Field interface (which means it’s also a Property), so you get its value by using getValue(). You can also use a ValueChangeListener. The value returned is a Set:
TokenField f = new TokenField("Add tags");
p.addComponent(f);
f.addListener(new ValueChangeListener() {
public void valueChange(ValueChangeEvent event) {
Set tokens = (Set)event.getProperty().getValue();
getWindow().showNotification("Tokens: "+ tokens);
}
});
Hope this helps!
…I should really add this snippet to the examples - thanks for making me notice that
This add-on is just what I was looking for!
Any ideas about how I can use it in a form with a FieldFactory? I want to get the tags as a List preferably of the same type as the BeanItemContainer.
One feature I am currently missing is to add an icon to a label, e.g., a flag next to the name of a Country. Is there a way to customize the current component to include this feature, or does the component itself needs to be extended with the ComboBox’s itemIcon feature?
I am currently trying the same.
I always get an ConversionException because PropertyFormatter tries to cast from HashSet containing the Tags to a String, which is abviously not possible.
I also tried to subclass PropertyFormatter and implemented parse/format methods which do this convertion.
It seems to me that Vaadin-Formfields are generally not really compatible with lists?!
Would like to hear about your further experiences.
I don’t know about this add-on, but as a general comment: forms and fields certainly are compatible with various data structures, and e.g. using a list in multi-select mode will use a Set as its value. However, Property
Formatter only handles conversions between a String and some other representation.
Support for easy conversion of values between a field and the underlying Property should be improved in the future.
The
CustomField add-on (including the class FieldWrapper in it, which might be of use for you) does support other conversions and provides a PropertyConverter interface.
Below is how i used it in a form FieldFactory… Hope this helps!
else if ("roles".equals(pid)) {
// We want this to be vertical
VerticalLayout layout = new VerticalLayout();
layout.setSpacing(true);
rolesField = new TokenField(SystemMsg.USER_ROLES.get(), layout) {
private static final long serialVersionUID = -6343481987196066377L;
// Display the dialog if not in 'role list', otherwise just add
@SuppressWarnings("unchecked")
protected void onTokenInput(Object tokenId) {
Set<Object> set = (Set<Object>) getValue();
Role role = new Role(tokenId.toString());
if (set != null && set.contains(role)) {
// duplicate role
getWindow().showNotification(
getTokenCaption(tokenId) + " is already added");
} else {
if (!cb.containsId(tokenId)) {
// don't add directly,
// show custom "add to role" dialog
getWindow().addWindow(new EditRoleWindow(role, this));
} else {
// it's in the role list, just add
addToken(tokenId);
}
}
}
// show confirm dialog
protected void onTokenClick(final Object tokenId) {
getWindow().addWindow(new RemoveWindow((Role) tokenId, this));
}
// just delete, no confirm
protected void onTokenDelete(Object tokenId) {
this.removeToken(tokenId);
}
protected void configureTokenButton(Object tokenId, Button button) {
super.configureTokenButton(tokenId, button);
// custom caption
// button.setCaption(getTokenCaption(tokenId));
button.setCaption(((Role) tokenId).getName());
// width
button.setWidth("100%");
if (!cb.containsId(tokenId)) {
// it's not in the role; style
button.addStyleName(TokenField.STYLE_BUTTON_EMPHAZISED);
}
}
public void commit() {
Set<Object> set = (Set<Object>) getValue();
List<Role> roles = new ArrayList<Role>();
Iterator it = set.iterator();
while(it.hasNext())
roles.add((Role)it.next());
user.setRoles(roles);
FacadeFactory.getFacade().store(user);
getWindow().showNotification("Information about this user saved.");
}
};
// This would turn on the "fake" look:
rolesField.setStyleName(TokenField.STYLE_TOKENFIELD);
rolesField.setWidth("200px");
rolesField.setInputWidth("200px");
rolesField.setContainerDataSource(roleContainer); // container for role input combobox
rolesField.setRequired(true);
rolesField.setImmediate(true);
rolesField.setFilteringMode(ComboBox.FILTERINGMODE_CONTAINS); // suggest
rolesField.setTokenCaptionPropertyId("name"); // use name in input
rolesField.setTokenCaptionMode(ComboBox.ITEM_CAPTION_MODE_PROPERTY);
rolesField.setInputPrompt("Enter the role name");
rolesField.setRememberNewTokens(false); // we'll do this via the dialog
// Display the current roles
List<Role> roles = user.getRoles();
for (Role role : roles) {
rolesField.addToken(role);
}
return rolesField;
}
return field;
}
I want to ask how can I get value of TokenField and change it to string, because I want to set value of TokenField in TextArea. I know that there are some methods like getValue() and toString(), but using getValue() I have nothing.
Really great component, and easy to use.
I only found it confusing when i wanted to get selected tokens. I used getTokenIds() instead of getValue().
I think it would be really usefull to add getTokens() method to TokenField class.
When using a fixed width tokenField and cssLayout, it would be nice the input box to expand to the remaining space, instead of leaving it unused. I have tried to do the trick with CSS styling, with no luck. Do you think this can be achieved this using CSS, or should this be achieved via component source modification?
This control is exactly what I want to use, thank you! One small issue under Vaadin 7 to do with all the refactoring going on… the 7 version needs a re-compile against a corrected import since using the control now yields a compile error:
“The type com.vaadin.terminal.Sizeable$Unit cannot be resolved. It is indirectly referenced from required .class files”
I’d fix myself, but I’m not really confident messing about with plug-ins yet.