Handling text input

When you use text input controls, such as TextArea and TextField, in your apps, you probably want to capture the text that users type in these fields and respond to it in some way. For example, your app might provide text fields that let a user add entries to a list. When the user taps Enter on the virtual keyboard, your app updates the list with the new entry.

You can use the input property (and its associated class, TextInputProperties) of a TextArea or TextField to respond to user input. The TextInputProperties class includes a submitted() signal that you can use to take action when a user taps Enter. Here's how to create a TextField that handles user input in QML. When a user types in the field and taps Enter, a Label is updated with the text that the user typed.

import bb.cascades 1.0
 
Page {
    content: Container {
	    TextField {
	        id: inputField      

	        input {
	            onSubmitted: {
	                label.text = inputField.text
	            }
	        }
	    }
	    
	    Label {
	        id: label
	        preferredWidth: 700
	        
	        text: ""
	    }
    }
}

The TextInputProperties class includes a property called submitKey that you can use to customize the text that appears on the Enter key on the virtual keyboard. You can use values from the SubmitKey::Type enumeration to specify the text that you want. For example, you can specify SubmitKey::Go to use "Go" as the text on this key, and you can specify SubmitKey::Done to use "Done" as the text. When you use one of the values from SubmitKey, the text on the Enter key is localized and displays in the language that users specify on their devices.

Here's an example of how to use the submitKey property on a TextField:

TextField {
    input {
        submitKey: SubmitKey.Done
	            
        onSubmitted: {
            // Handle the text that was typed
        }
    }
}

Validating text input

Depending on the text that your app is designed to handle, you might want to make sure that the text conforms to a certain set of criteria. For example, you could ensure that a username contains only letters and numbers, or you could enforce a minimum length requirement for a password. If you use a TextField to capture text input in your app, you can attach a validator to the field to validate the text that a user types.

A validator lets you test the contents of a TextField and determine whether the contents are valid based on criteria that you specify. A validator is represented by the Validator class and contains several properties that help you manage its behavior. The state property represents the current validation state of the validator (such as valid, invalid, or unknown). These possible states are specified in the ValidationState::Type enumeration. The valid property contains a Boolean value that indicates whether validation was successful or not. This property is true if the state property is ValidationState::Valid, and is false if the state property is ValidationState::Invalid or if validation hasn't been performed yet.

When the text in the TextField is valid, a green checkmark appears on the right side of the field. When the text is invalid, a red exclamation mark appears. You can use the errorMessage property to specify a message that you want to display when the contents of the TextField are invalid. Users can tap the red exclamation mark on an invalid field to display the error message.

Screen showing examples of text validators.

You can also specify a mode for the Validator by using the mode property. Validation modes are specified in the ValidationMode::Type enumeration and determine when the contents of the TextField are validated. For example, you might want to validate the contents only when the TextField loses focus. In this case, you can specify a mode of ValidationMode::FocusLost. If you want to validate the contents as the user is typing, you can enable immediate validation by using the ValidationMode::Immediate mode.

In some cases, you might not want the contents of a TextField to be validated automatically. Instead, your app could validate the contents manually based on an action that you specify, such as navigating to a new screen or clicking a button. You can use the ValidationMode::Custom mode to indicate that you don't want your TextField contents validated automatically. When you use this mode, you need to manually request validation of the contents of your TextField.

The following sections include examples of how to use both approaches (automatic and manual validation).

Validating text automatically

When you specify a mode for your validator (other than ValidationMode::Custom), the validate() signal is emitted whenever the validation conditions for that mode are met. For example, if you use ValidationMode::Immediate, the validate() signal is emitted whenever the text in the TextField changes. You can respond to this signal by using the onValidate signal handler in QML, or by connecting the signal to a slot function in C++. In your signal handler or slot function, you can perform your test to see if the contents are valid and then set the state property accordingly.

Here's how you can validate the contents of a TextField in QML. In this example, the validation mode is set to ValidationMode::Immediate, and if the length of the text exceeds 10 characters, the field is marked as invalid.

import bb.cascades 1.0

Page {
    Container {
        Label {
            text: "Type a username (10 characters maximum)."
        }
        TextField {
            id: myTextField

            validator: Validator {
                mode: ValidationMode.Immediate
                errorMessage: "Your username must be 10 characters or fewer."
                
                onValidate: {
                    if (myTextField.text.length <= 10)
                        state = ValidationState.Valid;
                    else
                        state = ValidationState.Invalid;
                }
            }
        }
    }
}

You can perform the same validation in C++. The following example assumes that you create an onValidate() slot function to handle the validate() signal, and that this slot function checks the length of the text in the TextField and sets the validation state appropriately.

// Create the UI controls
Page *root = new Page();
Container *topContainer = new Container();
Label *myLabel = new Label("Type a username (10 characters maximum).");
TextField *myTextField = new TextField();

// Create the validator
Validator *myValidator = Validator::create()
        .errorMessage("Your username must be 10 characters or fewer.")
        .mode(ValidationMode::Immediate);

// Connect the validator's validate() signal to a slot function.
// If any Q_ASSERT statement(s) indicate that the slot failed to connect to 
// the signal, make sure you know exactly why this has happened. This is not
// normal, and will cause your app to stop working!!
bool connectResult;

// Since the variable is not used in the app, this is added to avoid a 
// compiler warning.
Q_UNUSED(connectResult);

connectResult = QObject::connect(myValidator, SIGNAL(validate()),
                            this, SLOT(onValidate()));

// This is only available in Debug builds.
Q_ASSERT(res);

// Attach the validator to the text field and add the label and text field to
// the top-level container
myTextField->setValidator(myValidator);
topContainer->add(myLabel);
topContainer->add(myTextField);

Validating text manually

If you use the Custom validation mode, the validate() signal isn't emitted at all. Instead, you need to specifically request validation when you want to check the contents of a TextField for validity. There are two ways that you can request validation. You can use the Boolean property validationRequested to indicate that you want validation to be performed, and then listen for changes to this property by using the validationRequestedChanged() signal. Or, you can simply emit the validate() signal whenever you want your TextField to be validated.

Here's how to manually validate the text in a TextField in QML. A button is included, and when this button is pressed, the text in the TextField is validated.

import bb.cascades 1.0

Page {
    Container {
        Label {
            text: "Type a username (10 characters maximum)."
        }
        TextField {
            id: myTextField

            validator: Validator {
                id: myValidator
                mode: ValidationMode.Custom
                errorMessage: "Your username must be 10 characters or fewer."
                
                onValidate: {
                    if (myTextField.text.length <= 10)
                    	state = ValidationState.Valid;
                    else
                    	state = ValidationState.Invalid;
                }
            }
        }
        Button {
            text: "Validate"
            
            onClicked: {
                myValidator.validate();
            }
        }
    }
}

You can also achieve the same results in C++. Similar to the C++ example that was presented in the previous section, this example assumes that you've created both an onValidate() slot function (to perform the validation check) and an onClicked() slot function (to handle the clicked() signal and emit the validate() signal).

// Create the UI controls
Page *root = new Page();
Container *topContainer = new Container();
Label *myLabel = new Label("Type a username (10 characters maximum).");
TextField *myTextField = new TextField();
Button *validateButton = new Button("Validate");

// Create the validator
Validator *myValidator = Validator::create()
        .errorMessage("Your username must be 10 characters or fewer.")
        .mode(ValidationMode::Custom);

// Connect the validator's validate() signal to a slot function. 
// If any Q_ASSERT statement(s) indicate that the slot failed to connect to 
// the signal, make sure you know exactly why this has happened. This is not
// normal, and will cause your app to stop working!!
bool connectResult;

// Since the variable is not used in the app, this is added to avoid a 
// compiler warning.
Q_UNUSED(connectResult);

connectResult = QObject::connect(myValidator, SIGNAL(validate()),
                            this, SLOT(onValidate()));

// This is only available in Debug builds.
Q_ASSERT(connectResult);

// Connect the button's clicked() signal to a slot function.
connectResult = QObject::connect(validateButton, SIGNAL(clicked()),
                       this, SLOT(onClicked()));

// This is only available in Debug builds.
Q_ASSERT(connectResult);

// Attach the validator to the text field and add the label, text field, and
// button to the top-level container
myTextField->setValidator(myValidator);
topContainer->add(myLabel);
topContainer->add(myTextField);
topContainer->add(validateButton);

Last modified: 2013-12-21



Got questions about leaving a comment? Get answers from our Disqus FAQ.

comments powered by Disqus