A validator is used to validate user input according to pre-defined rules.
A validator may have a split implementation to provide both validation at
the client-side (which gives instant feed-back to the user while
editing), and server-side validation (to be sure that the client was not
tampered with). The feed-back given by (client-side and server-side)
validation is reflected in the style class of the form field: a style
class of Wt-invalid
is set for a field that is invalid.
The WValidator only checks that mandatory fields are not empty. Validated input can have one of the following states:
If these validators are not suitable, you can inherit from this class,
and provide a suitable implementation to validate()
which does
the server-side validation. If you want to provide client-side validation
for your own validator, you may also reimplement javaScriptValidate()
.
In entirely the same way, a date validator can be used to
validate date input with a WDateEdit
or
WDatePicker
. You can limit the date range of the
calendar using setBottom()
and setTop()
.
#include <Wt/WTemplate.h>
#include <Wt/WDate.h>
#include <Wt/WDateValidator.h>
#include <Wt/WLabel.h>
#include <Wt/WDateEdit.h>
#include <Wt/WPushButton.h>
#include <Wt/WValidator.h>
auto t = std::make_unique<Wt::WTemplate>(Wt::WString::tr("date-template"));
t->addFunction("id", &Wt::WTemplate::Functions::id);
auto dateEdit = t->bindWidget("birth-date", std::make_unique<Wt::WDateEdit>());
auto dv = std::make_shared<Wt::WDateValidator>();
dv->setBottom(Wt::WDate(1900, 1, 1));
dv->setTop(Wt::WDate::currentDate());
dv->setFormat("dd/MM/yyyy");
dv->setMandatory(true);
dv->setInvalidBlankText("A birthdate is mandatory!");
dv->setInvalidNotADateText("You should enter a date in the format "
"\"dd/MM/yyyy\"!");
dv->setInvalidTooEarlyText
(Wt::WString("That's too early... The date must be {1} or later!"
"").arg(dv->bottom().toString("dd/MM/yyyy")));
dv->setInvalidTooLateText
(Wt::WString("That's too late... The date must be {1} or earlier!"
"").arg(dv->top().toString("dd/MM/yyyy")));
dateEdit->setValidator(dv);
auto button = t->bindWidget("button", std::make_unique<Wt::WPushButton>("Ok"));
auto out = t->bindWidget("info", std::make_unique<Wt::WText>());
out->setInline(false);
out->hide();
button->clicked().connect([=] {
out->show();
Wt::WValidator::Result result = dv->validate(dateEdit->text());
if (result.state() == Wt::ValidationState::Valid) {
Wt::WDate d = Wt::WDate::currentServerDate();
int years = d.year() - dateEdit->date().year();
int days = d.daysTo(dateEdit->date().addYears(years));
if (days < 0)
days = d.daysTo( dateEdit->date().addYears(years + 1) );
out->setText("<p>In " + std::to_string(days) +
" days, we will be celebrating your next anniversary!</p>");
out->setStyleClass("alert alert-success");
} else {
dateEdit->setFocus(true);
out->setText(result.message());
out->setStyleClass("alert alert-danger");
}
});
dateEdit->enterPressed().connect([=] {
button->clicked().emit(Wt::WMouseEvent());
});
A more convenient way to perform validation is to implement a form model (a specialisation of WFormModel) and a complementary template-based view (a specialisation of WTemplateFormView). In this way you can validate the values entered at the server-side.
The form model implements field data and validation handling for (simple)
form-based views. It provides a standard way for views to perform field
validation, and react to validation results.
Each field has a string literal assigned to it. The string literal
uniquely identifies the field. For each field, its value, the visibility,
whether the field is read-only, and its current validation status is
managed by the model.
In addition, you will typically specialize the class to customize the
validation and application logic. Although it can be setup to use
WValidator
objects for individual fields, you could also create a
validator to simultaneously validate interdependent fields.
A model is typically used by a view which renders the fields configured in the model, updates the model values, invokes and reflects the validation status. See Forms for more details on implementing forms.
Here is an example with the same behavior as the previous example. It
also uses the same XML template. The contents of the variable name
'age-info' in the template depends on the outcome of the method
validate()
of the model.
#include <Wt/WFormModel.h>
#include <Wt/WIntValidator.h>
#include <Wt/WLineEdit.h>
#include <Wt/WPushButton.h>
#include <Wt/WValidator.h>
#include <Wt/WTemplateFormView.h>
class AgeFormModel : public Wt::WFormModel
{
public:
static const Field AgeField;
// inline constructor
AgeFormModel() : WFormModel()
{
addField(AgeField);
setValidator(AgeField, createAgeValidator());
setValue(AgeField, std::string());
}
private:
std::shared_ptr<Wt::WValidator> createAgeValidator() {
return std::make_shared<Wt::WIntValidator>(0, 150);
}
};
const Wt::WFormModel::Field AgeFormModel::AgeField = "age";
class AgeFormView : public Wt::WTemplateFormView
{
public:
// inline constructor
AgeFormView() {
model_ = std::make_unique<AgeFormModel>();
setTemplateText(tr("validation-template"));
setFormWidget(AgeFormModel::AgeField, std::make_unique<Wt::WLineEdit>());
auto button = bindWidget("button",
std::make_unique<Wt::WPushButton>("Save"));
button->clicked().connect(this, &AgeFormView::process);
updateView(model_.get());
}
private:
void process() {
updateModel(model_.get());
if (model_->validate()) {
// Udate the view: Delete any validation message in the view, etc.
updateView(model_.get());
bindString("age-info",
Wt::WString("Age of {1} is saved!")
.arg(Wt::asString(model_->value(AgeFormModel::AgeField))));
} else {
updateView(model_.get());
// Set the focus on the line edit.
Wt::WLineEdit *viewField =
resolve<Wt::WLineEdit *>(AgeFormModel::AgeField);
viewField->setFocus(true);
}
}
std::unique_ptr<AgeFormModel> model_;
};
auto view = std::make_unique<AgeFormView>();