In some cases, we need to use text fields with limited character length, usually for forms that submit data to database. It is nice to tell the user how many characters remain. For that case, we can create our custom text field with a counter, as shown in the following screenshot. In this recipe, we will show how to do it.
Carry out the following steps to create a TextField
with a counter:
Demo
as follows:public class Demo extends UI {…}
vaadin
. Then we select the item Vaadin Widget and click on the Next button, as shown in the following screenshot:com.packtpub.vaadin.widget
. The name of our new component will be CountedTextField
and as a superclass we set com.vaadin.ui.TextField
. After filling in the properties, we click on the Finish button, as shown in the following screenshot:CountedTextFieldWidget
. This client-side widget will extend Composite
. The Composite
is a type of widget that wraps another widget. It hides the wrapped widget's methods.import com.google.gwt.user.client.ui.Composite; public class CountedTextFieldWidget extends Composite { … }
TextBox
for user input and Label
for showing the number of characters in TextBox
. These two parts will be added to the HorizontalPanel
because we want to show the label on the right side of the textbox. We create instances of these classes at the beginning of the CountedTextFieldWidget
class. The generated constant CLASSNAME
will be used to set default CSS style name of our widget.import com.google.gwt.user.client.ui.TextBox; import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.HorizontalPanel; … private TextBox textBox = new TextBox(); private Label countLabel = new Label("0"); private HorizontalPanel panel = new HorizontalPanel(); public static final String CLASSNAME="countedtextfield";
Widget
methods on this object. Otherwise, our widget doesn't appear on the web page. This method may only be called once for a given composite. Then we set the name of our used CSS style and we add the created widgets to the panel.public CountedTextFieldWidget() { initWidget(panel); setStyleName(CLASSNAME); panel.add(textBox); panel.add(countLabel); }
CountedTextFieldWidget
. For example, if we want to return text from our widget, we simply add the getText()
method that hides implementation of the inner textBox.getText()
method.public String getText() { return textBox.getText(); } public void setText(String text) { textBox.setText(text); } public void setCount(int count) { countLabel.setText("" + count); }
KeyUpHandler
. Each addXxxHandler()
method returns the HandlerRegistration
interface. This interface contains the removeHandler()
method that can be used to remove the handler from the widget.public HandlerRegistration addKeyUpHandler( KeyUpHandler handler) { return textBox.addKeyUpHandler(handler); }
CountedTextFieldState
class, we only rewrite the name of the primary style. We will do it using the non-static block that is executed before any constructor. The primaryStyleName
string is inherited from the AbstractFieldState
class. In that class, it's set to v-textfield
. We remove this style because it conflicts with the default GWT style gwt-TextBox
.public class CountedTextFieldState extends com.vaadin.shared.ui.textfield.AbstractTextFieldState { { primaryStyleName = null; } }
CountedTextFieldConnector
class. We don't need the generated stuff in the constructor. So, we clean the whole constructor and add KeyUpHandler
. On the KeyUp
event we update the value of the countLabel
object. It causes the count of characters to be updated immediately after each key press.public CountedTextFieldConnector() { getWidget().addKeyUpHandler(new KeyUpHandler() { @Override public void onKeyUp(KeyUpEvent event) { String text = getWidget().getText(); getWidget().setCount(text.length()); } }); }
onStateChanged()
. After each change of state, this method will update the value of text
and count
on our created widget. The variable text
is from the inherited AbstractTextFieldState
class.@Override public void onStateChanged( StateChangeEvent stateChangeEvent) { super.onStateChanged(stateChangeEvent); final String text = getState().text; getWidget().setText(text); getWidget().setCount(text.length()); }
CountedTextField
, we can delete the generated stuff except the getState()
method. Then we insert the overridden getter and setter of the component's text
value. This value is propagated through the CountedTextFieldState
component. Sending events from the server to the client works automatically in Vaadin. But the changes on the client side aren't automatically sent to the server-side component. For this purpose, we can use the Remote Procedure Calls (RPC) mechanism. The link to the Vaadin website about this mechanism is added in the See also section at the end of this recipe.public class CountedTextField extends com.vaadin.ui.TextField { @Override public CountedTextFieldState getState() { return (CountedTextFieldState) super.getState(); } @Override public String getValue() { return getState().text; } @Override public void setValue(String value) { getState().text = value; } }
CountedTextFieldClientRpc
and CountedTextFieldServerRpc
aren't used in our widget. We can delete them.WebContent/VAADIN/widgetsets
folder.public class Demo extends UI { @Override protected void init(VaadinRequest request) { setContent(new CountedTextField()); } }
Now we can run the server and open our Demo
application in a web browser.
We created our custom text field with a counter. The counter shows how many characters are in the textbox. If the user enters some text to this field, then the onKeyUp()
method in the KeyUpHandler
on the CountedTextFieldWidget
is called. Inside this method, we set the value of the label counter. It causes the counter to be updated immediately after each keystroke. Because changes on the client side aren't automatically sent to the server-side component, we can use the RPC mechanism that is described on the Vaadin website mentioned in the See also section.
The Vaadin Plug-in for Eclipse can automatically compile the widget set after every client-side source file. This function is suspended by default. If we want to activate it, we can do it in the project properties in the following way. It can help us because we'll still have the last compiled widget set but it can use a lot of CPU and slow down the computer.
3.15.149.45