Vaadin TextBox: Numbers and decimal only. - vaadin

How do I get a textbox to give me an error if anything other than numbers and/or decimals are submitted?

You need to add a validator to the text field.
textField.addValidator(new Validator());
There is not a validator that checks if the value is a number or not in Vaadin, so you need to create a custom one:
private class MyValidator implements Validator {
#Override
public void validate(Object value)
throws InvalidValueException {
if (!(value instanceof Integer &&
(value instanceof Double)) {
throw new InvalidValueException("The value is not a number");
}
}
}
Now you can add your custom validator to your field:
textField.addValidator(new MyValidator());
More info about validators here.

private class MyValidator implements Validator {
#Override
public void validate(Object value) throws InvalidValueException {
try {
// new Integer(text);
new Double(value.toString());
} catch (NumberFormatException e) {
throw new InvalidValueException("The value is not a number");
}
}
}

Related

How to modify binded value in MVVM Cross

I have a model from my json in a Xamarin MVVM app(ios). I want to add the "%" after the value? in the list "coinmarketcaplist" contains the value 24h_change, this is the value I want to add a % to, it's a string. I know that I should use a getter for it, but I don't know how since I'm fairly new to this. below is my ViewModel code:
public class CMCTableViewModel : MvxViewModel
{
protected readonly ICoinMarketCapService _coinMarketCapService;
public CMCTableViewModel(ICoinMarketCapService coinMarketCapService)
{
_coinMarketCapService = coinMarketCapService;
LoadData();
}
private List<CoinMarketCapModel> _coinMarketCapModelList;
public List<CoinMarketCapModel> CoinMarketCapModelList
{
get
{
return _coinMarketCapModelList;
}
set
{
_coinMarketCapModelList = value;
RaisePropertyChanged(() => CoinMarketCapModelList);
}
}
public async void LoadData()
{
CoinMarketCapModelList = await _coinMarketCapService.GetCoins();
}
}
TableCell:
internal static readonly NSString Identifier = new NSString("CMCTableCell");
public override void LayoutSubviews()
{
base.LayoutSubviews();
MvxFluentBindingDescriptionSet<CMCTableCell, CoinMarketCapModel> set = new MvxFluentBindingDescriptionSet<CMCTableCell, CoinMarketCapModel>(this);
set.Bind(lblName).To(res => res.Name);
set.Bind(lblPrice).To(res => res.percent_change_24h);
set.Bind(imgCoin)
.For(img => img.Image)
.To(res => res.image)
.WithConversion<StringToImageConverter>();
set.Apply();
}
}
edit: added cellview
Use a converter in your binding:
1) Define converter:
public class StringFormatValueConverter : MvxValueConverter
{
public override object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null)
return null;
if (parameter == null)
return value;
return string.Format(parameter.ToString(), value);
}
}
2) Use it in your binding:
set.Bind(lblPrice).To(res => res.percent_change_24h).WithConversion<StringFormatValueConverter>("{0} %");
You can use this converter when you want to modify the input string by adding something around it, for example unit or currency

Vaadin Validate date, not empty

Im trying to write validation in Vaadin but I don't understand how to check if date field is empty
I wrote something like this
#Override
public void setConfiguration(EditorConfiguration editorConfiguration) {
boolean required = ((DateFieldConfiguration) editorConfiguration).isRequired();
if (required == true) {
setRequiredIndicatorVisible(true);
addValueChangeListener(event -> validate(event.getSource().getDefaultValidator(), event.getValue()));
}
}
private void validate(Validator<LocalDate> defaultValidator, LocalDate localDate) {
binder.forField(this).withValidator(validator).asRequired("Mandatory").bind(s -> getValue(),
(b, v) -> setValue(v));
}
I have achived a validation with a text field:
String Validator code
public class VaadinStringEditor extends TextField implements HasValueComponent<String> {
/**
*
*/
private static final long serialVersionUID = 6271513226609012483L;
private Binder<String> binder;
#PostConstruct
public void init() {
setWidth("100%");
binder = new Binder<>();
}
#Override
public void initDefaults() {
setValue("");
binder.validate();
}
#Override
public void setConfiguration(EditorConfiguration editorConfiguration) {
Validator<String> validator = ((TextFieldConfiguration) editorConfiguration).getValidator();
if (validator != null) {
binder.forField(this).withValidator(validator).asRequired("Mandatory").bind(s -> getValue(),
(b, v) -> setValue(v));
}
and I valid it here:
question.setEditorConfiguration(new TextFieldConfiguration(textRequiredValidator()));
Validator:
private Validator<String> textRequiredValidator() {
return Validator.from(v -> v != null && StringUtils.trimAllWhitespace((String) v).length() != 0,
, "Not empty");
}
You should use com.vaadin.ui.DateField for LocalDate values. Have a look at the following example.
Example bean:
public class MyBean {
private LocalDate created;
public LocalDate getCreated() {
return created;
}
public void setCreated(LocalDate created) {
this.created = created;
}
}
Editor
DateField dateField = new DateField("Date selector");
binder.forField(dateField)
.bind(MyBean::getCreated, MyBean::setCreated);
If for some reason you would like to have com.vaadin.ui.TextField for editing date, then you need to set converter like this:
Binder<MyBean> binder = new Binder<>();
TextField textDateField = new TextField("Date here:");
binder.forField(textDateField)
.withNullRepresentation("")
.withConverter(new StringToLocalDateConverter())
.bind(MyBean::getCreated, MyBean::setCreated);
Converter implementation:
public class StringToLocalDateConverter implements Converter<String, LocalDate> {
#Override
public Result<LocalDate> convertToModel(String userInput, ValueContext valueContext) {
try {
return Result.ok(LocalDate.parse(userInput));
} catch (RuntimeException e) {
return Result.error("Invalid value");
}
}
#Override
public String convertToPresentation(LocalDate value, ValueContext valueContext) {
return Objects.toString(value, "");
}
}
Note that this converter does not utilise ValueContext object that contains information that should be taken into account in more complex cases. For example, user locale should be handled.

Adapt field to store to database

Say I have a field content that is a json. I would like to store it in database so that my domain class keeps only the 1 field only. (It's more of a brain task ;-)
class MyDomain{
def content
static constraints = {
content nullable: false, blank: false, sqlType: "text" // adapter from JSON to String??
}
def beforeInsert(){
content = content.toString()
}
def beforeUpdate(){
content = content.toString()
}
def afterInsert(){
content = JSON.parse(content) as JSON
}
def afterUpdate(){
content = JSON.parse(content) as JSON
}
def onLoad(){
content = JSON.parse(content) as JSON
}
}
I want my domain object to expose only content so I don't want to use another field like String contentAsText because it would be visible outside.
In the whole GORM documentation I haven't found a thing how to manage it. I've tried beforeValidate()/beforeInsert() and onLoad() methods but no luck...
How can I adapt the value before it gets persisted?
You can define a custom hibernate user-type for JSONElement as described here: https://stackoverflow.com/a/28655708/607038
In domain class constraints:
static constraints = {
content type: JSONObjectUserType
}
User Type Class:
import org.grails.web.json.JSONObject
import org.hibernate.HibernateException
import org.hibernate.engine.spi.SessionImplementor
import org.hibernate.type.StandardBasicTypes
import org.hibernate.usertype.EnhancedUserType
import java.sql.PreparedStatement
import java.sql.ResultSet
import java.sql.SQLException
import java.sql.Types
class JSONObjectUserType implements EnhancedUserType, Serializable {
private static final int[] SQL_TYPES = [Types.VARCHAR]
#Override
public int[] sqlTypes() {
return SQL_TYPES
}
#Override
public Class returnedClass() {
return JSONObject.class
}
#Override
public boolean equals(Object x, Object y) throws HibernateException {
if (x == y) {
return true
}
if (x == null || y == null) {
return false
}
JSONObject zx = (JSONObject) x
JSONObject zy = (JSONObject) y
return zx.equals(zy)
}
#Override
public int hashCode(Object object) throws HibernateException {
return object.hashCode()
}
#Override
public Object nullSafeGet(ResultSet resultSet, String[] names, SessionImplementor session, Object owner)
throws HibernateException, SQLException {
Object jsonObject = StandardBasicTypes.STRING.nullSafeGet(resultSet, names, session, owner)
if (jsonObject == null) {
return null
}
return new JSONObject((String) jsonObject)
}
#Override
public void nullSafeSet(PreparedStatement preparedStatement, Object value, int index, SessionImplementor session)
throws HibernateException, SQLException {
if (value == null) {
StandardBasicTypes.STRING.nullSafeSet(preparedStatement, null, index, session)
} else {
JSONObject jsonObject = (JSONObject) value
StandardBasicTypes.STRING.nullSafeSet(preparedStatement, jsonObject.toString(), index, session)
}
}
#Override
public Object deepCopy(Object value) throws HibernateException {
return value
}
#Override
public boolean isMutable() {
return false
}
#Override
public Serializable disassemble(Object value) throws HibernateException {
return (Serializable) value
}
#Override
public Object assemble(Serializable cached, Object value) throws HibernateException {
return cached
}
#Override
public Object replace(Object original, Object target, Object owner) throws HibernateException {
return original
}
#Override
public String objectToSQLString(Object object) {
throw new UnsupportedOperationException()
}
#Override
public String toXMLString(Object object) {
return object.toString()
}
#Override
public Object fromXMLString(String string) {
return new JSONObject(string)
}
}
class MyDomain{
JSONElement content
static constraints = {
content nullable: false, blank: false, sqlType: "text" // adapter from Map to String??
}
def setContent(String textContent){
content = JSON.parse(textContent)
}
}
I had to do 2 things.
replace def content with JSON content so that it gets persisted, see Grails Domain Constructor is not Groovy Constructor
Convert a json string back to json via def setContent().
As content is JSONElement use JSONObject and JSONArray as concrete classes.

Grails, property names in embedded object in domain class causing problems

I'm using grails 2.3.4 and I have a domain class that embeds an object. The embedded object has a property called 'version' and it seems that this is conflicting with the 'version'-field automatically added to the database-table by GORM. The result is that the 'version'-field belonging to my embedded object isn't created in the database and as a consequence my application doesn't work properly.
My code looks like this:
class Thing {
String someText
EmbeddedThing embeddedThing
Date someDate
static embedded = ['embeddedThing']
static constraints = {
embeddedThing(unique: true)
}
}
class EmbeddedThing {
String textOfSomeSort
String version
String textOfSomeOtherSort
}
You might think that a quick fix is to rename the 'version'-property of the embedded object but the class belongs to an included sub-project (i.e. a JAR-file) that I'm not allowed to touch since other projects use it. So the solution needs to be done completely within my domain class, or at least in a manner that doesn't change the class of the embedded object.
version is a special column name, you should rename your version field within your EmbeddedThin class
I actually found a solution to this problem by using a Hibernate UserType to represent the EmbeddedThing-class.
My code now looks like this and works perfectly:
Thing.groovy:
import EmbeddedThingUserType
class Thing {
String someText
EmbeddedThing embeddedThing
Date someDate
static embedded = ['embeddedThing']
static mapping = {
version false
embeddedThing type: EmbeddedThingUserType, {
column name: "embedded_thing_text"
column name: "embedded_thing_version"
column name: "embedded_thing_other_text"
}
}
static constraints = {
embeddedThing(unique: true)
}
}
EmbeddedThing.groovy:
class EmbeddedThing {
String textOfSomeSort
String version
String textOfSomeOtherSort
}
EmbeddedThingUserType.groovy:
class EmbeddedThingUserType implements UserType {
int[] sqlTypes() {
return [StringType.INSTANCE.sqlType(),
StringType.INSTANCE.sqlType(),
StringType.INSTANCE.sqlType()]
}
Class returnedClass() {
return EmbeddedThing
}
public Object nullSafeGet(ResultSet resultSet, String[] names, Object owner)
throws HibernateException, SQLException {
if (resultSet && names) {
return new EmbeddedThing(
textOfSomeSort: resultSet?.getString(names[0] ?: '_missing_textOfSomeSort_'),
version: resultSet?.getString(names[1] ?: '_missing_version_'),
textOfSomeOtherSort: resultSet?.getString(names[2] ?: '_missing_textOfSomeOtherSort_'))
} else {
return null
}
}
public void nullSafeSet(PreparedStatement preparedStatement, Object value, int index)
throws HibernateException, SQLException {
if (value != null) {
preparedStatement.setString(index, value?.textOfSomeSort)
preparedStatement.setString(index + 1, value?.version)
preparedStatement.setString(index + 2, value?.textOfSomeOtherSort)
} else {
preparedStatement.setString(index, '_missing_textOfSomeSort_')
preparedStatement.setString(index + 1, '_missing_version_')
preparedStatement.setString(index + 2, '_missing_textOfSomeOtherSort_')
}
}
#Override
public boolean isMutable() {
return false
}
#Override
public boolean equals(Object x, Object y) throws HibernateException {
return x.equals(y)
}
#Override
public int hashCode(Object x) throws HibernateException {
assert (x != null)
return x.hashCode()
}
#Override
public Object deepCopy(Object value) throws HibernateException {
return value
}
#Override
public Object replace(Object original, Object target, Object owner)
throws HibernateException {
return original
}
#Override
public Serializable disassemble(Object value) throws HibernateException {
return (Serializable) value
}
#Override
public Object assemble(Serializable cached, Object owner)
throws HibernateException {
return cached
}
}
Config.groovy:
grails.gorm.default.mapping = {
'user-type'( type: EmbeddedThingUserType, class: EmbeddedThing)
}
Please try version false in your 'static mapping', for the 'EmbeddedThing' class.

How to validate Integers from a TextField in a table with a wrapper

I have a table where I'm using createField() to create the fields.
In editing mode, users are able to input text into the fields.
One of the columns in this table should only allow Integers and therefore I am using an IntegerRangeValidator.
The validation should be dynamic (as-you-type) and if the input is validated false, a little red exclamation mark should be shown and the tooltip should say something like "Only Integers allowed!".
To be able to show these exclamation marks and have this dynamic validation, I needed to use a wrapper that listens to textChanges every 200ms.
The problem is that the TextField is returning a String, so the validator interprets everything as Strings, even if the user has typed an integer into the field.
In Vaadin 7 - How do I validate Integers from a TextField that is inside a table when the validation is executed in an overriden textChange-method in a wrapper?
The createField-method:
#Override
public Field<?> createField(Container container, Object itemId, Object propertyId, com.vaadin.ui.Component uiContext) {
TextField tField = null;
tField = (TextField) super.createField(container, itemId, propertyId, uiContext);
tField.setBuffered(true);
addFieldListeners(tField);
if (propertyId.equals("age") {
tField.setRequired(true);
tField.setRequiredError("This field is required!");
// tField.setConverter(new StringToIntegerConverter()); <-- I also tried this, without success
tField.addValidator(new IntegerRangeValidator("Only Integers allowed!", 1, 150));
#SuppressWarnings({ "unchecked", "rawtypes" })
TableDataValidatingWrapper<TextField> wField = new TableDataValidatingWrapper(tField);
return wField;
} else {
return null;
}
}
The wrapper:
public class TableDataValidatingWrapper<T> extends CustomField<T> {
private static final long serialVersionUID = 1L;
protected Field<T> delegate;
public TableDataValidatingWrapper(final Field<T> delegate) {
this.delegate = delegate;
if (delegate instanceof TextField) {
final TextField textField = (TextField) delegate;
textField.setTextChangeEventMode(AbstractTextField.TextChangeEventMode.TIMEOUT);
textField.setTextChangeTimeout(200);
textField.setCaption("");
textField.addTextChangeListener(new FieldEvents.TextChangeListener() {
private static final long serialVersionUID = 1L;
#Override
public void textChange(FieldEvents.TextChangeEvent event) {
try {
textField.setValue(event.getText());
textField.validate();
} catch (EmptyValueException e) {
System.out.println("Caught exception " + e);
} catch (InvalidValueException e) {
System.out.println("Caught exception " + e);
} catch (Exception e) {
System.out.println("Caught unknown exception " + e);
}
}
});
}
}
// ... some other overridden methods
}
You can add an Converter to your TextField that converts Strings into Integers:
tField.setConverter(new StringToIntegerConverter());
tField.addValidator(new IntegerRangeValidator("Only Integers allowed!", 1, 150));
I solved this by using my own CustomIntegerRangeValidator for the String fields that should be validated as Integers, like so:
public class CustomIntegerRangeValidator extends AbstractValidator<String> {
private static final long serialVersionUID = 1L;
private IntegerRangeValidator integerRangeValidator;
public CustomIntegerRangeValidator(String errorMessage, Integer minValue, Integer maxValue) {
super(errorMessage);
this.integerRangeValidator = new IntegerRangeValidator(errorMessage, minValue, maxValue);
}
#Override
protected boolean isValidValue(String value) {
try {
Integer result = Integer.parseInt(value);
integerRangeValidator.validate(result);
return true;
} catch (NumberFormatException nfe) {
// TODO: handle exception
System.out.println("Cannot be parsed as Integer: " + nfe);
return false;
} catch (Exception e) {
// TODO: handle exception
System.out.println("Unknown exception: " + e);
return false;
}
}
#Override
public Class<String> getType() {
return String.class;
}
}

Resources