0

Issue with simpleConstraint

asked 2015-12-08 11:51:49 +0800

WilliamB gravatar image WilliamB
1609 1 6

I'm creating a weird component that can accept multiple type of input and do validation.

It has a custom attribut where the user type something and I'll generate a regex from the input. For now I'm just starting so depending on the language it ll change "." => "," or the opposite, hence the onChanging listener.

public class DecimalBox extends Textbox implements AfterCompose {

    private static final long serialVersionUID = 1L;

    private static final String FR_DECIMAL_SEPARATOR = ",";

    private static final String EN_DECIMAL_SEPARATOR = ".";

    private static final String LABEL_DESC_CHAMP = "validation.error.decimal";

    // ========================================================================
    // Attributs
    // ========================================================================

    private boolean isFrench = ((Locale) Sessions.getCurrent().getAttribute(org.zkoss.web.Attributes.PREFERRED_LOCALE)).equals(Locale.FRENCH);

    private Integer nbMaxNumber;

    private Integer nbDecimal;

    private String tooltipText;

    private String regex;

    // ========================================================================
    // Initialisation
    // ========================================================================

    public DecimalBox() {

        addEventListener("onChanging", new EventListener<InputEvent>() {

            /** {@inheritDoc} */
            @Override
            public void onEvent(final InputEvent pEvent) throws Exception {
                setValue(pEvent.getValue());
            }
        });
    }

    /** {@inheritDoc} */
    @Override
    public void afterCompose() {
        // Selon le type d'attribut renseigné, on va générer la contrainte et le tooltip
        if (nbMaxNumber != null && nbDecimal != null) {
            tooltipText = MessageFormat.format(Labels.getLabel(LABEL_DESC_CHAMP), (nbMaxNumber - nbDecimal), nbDecimal);
            regex = "([0-9]{1," + (nbMaxNumber - nbDecimal) + "}(,[0-9]{1," + nbDecimal + "}){0,1}){0,1}";
        }
        setTooltiptext(tooltipText);
        setConstraint(new SimpleConstraint(regex, tooltipText));
    }

    // ========================================================================
    // Méthodes privées
    // ========================================================================

    /** Format la string en mettant le bon caractère pour les décimal. */
    private String formatInput(final String pInput) {
        String result = pInput;
        if (isFrench) {
            result = StringUtils.replace(result, EN_DECIMAL_SEPARATOR, FR_DECIMAL_SEPARATOR);
        } else {
            result = StringUtils.replace(result, FR_DECIMAL_SEPARATOR, EN_DECIMAL_SEPARATOR);
        }

        return result;
    }

    // ========================================================================
    // Setters
    // ========================================================================

    /** {@inheritDoc} */
    @Override
    public void setValue(final String pValue) {
        super.setValue(formatInput(pValue));
    }

    public void setNumberConf(final String pNumberConf) {
        boolean wrongValue = false;
        if (StringUtils.isEmpty(pNumberConf)) {
            wrongValue = true;
        } else {
            String[] split = pNumberConf.split(",");
            if (split.length > 2) {
                wrongValue = true;
            } else {
                try {
                    nbMaxNumber = Integer.valueOf(split[0]);
                    if (split.length == 2) {
                        nbDecimal = Integer.valueOf(split[1]);

                        if (nbDecimal > nbMaxNumber) {
                            wrongValue = true;
                        }
                    }
                } catch (NumberFormatException e) {
                    wrongValue = true;
                }
            }
        }

        if (wrongValue) {
            throw new WrongValueException("numberConf doit contenir 1 chiffre ou 2 chiffres séparés par une virgule.");
        }
    }
}

The implementation :

<decimalbox numberConf="5,2"/>

In that case, I'll create a regex ([0-9]{1,3}(,[0-9]{1,2}){0,1}){0,1} Add it as a Simpleconstraint to my componenent in the Aftercompose

When I type stuff it seems to work fine, if i Type 3 decimal I get an error fine and if I go back to 2 it's all good, due to the onChanging event.

I see that I go through validation, after the SetValue trigger by the onChanging and it works fine if my input validate the regex.

the issue I've, is when I click outside of the box, the error popup always shows. And I do not understand why ...

I tried by wrapping my regex with "/" but then it's the onChanging event that always triggers ...

Why it's never simple with ZK .....

Thanks for your help

delete flag offensive retag edit

Comments

I'm thinking of onChange event as that is triggered when you lost the focus of textbox.

chillworld ( 2015-12-08 12:02:20 +0800 )edit

Yes but why the validation of onChange would not work? Do I really need to overide onChange and do the validation myself instead of using SimpleConstraint ???

WilliamB ( 2015-12-08 12:25:01 +0800 )edit

nah, you don't need to override that, normally when you lose focus you trigger the onChange and at that moment the databinding. (instant isn't set to true). With getValue you trigger the SimpleConstraint and he fails at that moment

chillworld ( 2015-12-08 13:10:14 +0800 )edit

But why does it fail? It's my question ... Since I'm catching the onChanging, and doing a setValue, it triggers the constraint check then, and find my content Valid.

But not when it does on onChange ?!

WilliamB ( 2015-12-08 13:25:40 +0800 )edit

What is wrong with my regex? It passes online regex parser and tester

WilliamB ( 2015-12-08 13:30:20 +0800 )edit

2 Answers

Sort by » oldest newest most voted
1

answered 2015-12-10 04:05:45 +0800

cor3000 gravatar image cor3000
4332 1 7
ZK Team

updated 2015-12-10 07:39:52 +0800

When using the constructor SimpleConstraint(String regex ,String errmsg) the regex is just a plain regex, and when surrounded by slashes they count as part of the expression.

In the single argument constructor the slashes are required by the parser to identify the regex between the slashes.

However this works only for simple regular expressions, when capture groups are used there is a bug ... I'll post soon.

Edit: posted the bug ZK-3017 containing a patch and workaround

Robert

link publish delete flag offensive edit
0

answered 2015-12-09 09:30:24 +0800

WilliamB gravatar image WilliamB
1609 1 6

updated 2015-12-09 10:05:34 +0800

OK Chill, first thanks for sticking around ;)

I finally found what is causing the issue : If I use the constructor with only the regex, it works fine.

setConstraint(new SimpleConstraint(regex));

The issue with the message triggering all the time is when I add a custom error message by using the 2 arguments contructor

setConstraint(new SimpleConstraint(regex, "toto"));

Tried adding ":" at the end of the regex, like when it's in the zul, to see if it helped but it didn't.

Looking into the code it doesn't work the same way to generate the pattern through both constructor.

So now i'm dwelling into ZK code to see where the issue comes from and create an issue ...

EDIT: Here what I found out :

  • If I use : public SimpleConstraint(String constraint)

_raw: /^([0-9]{1,3}(,[0-9]{1,2})?)?$/

_regex: ^([0-9]{1,3}(,[0-9]{1,2})?)?$

_errmsg : null

public String getClientConstraint() : '/^([0-9]{1,3}(,[0-9]{1,2})?)?$/'

  • If I use public SimpleConstraint(String regex, String errmsg) with wrapping "/"

_raw: null

_regex: /^([0-9]{1,3}(,[0-9]{1,2})?)?$/

_errmsg : myMsg

public String getClientConstraint() : new zul.inp.SimpleConstraint(0,'/^([0-9]{1,3}(,[0-9]{1,2})?)?$/','myMsg')

  • If I use public SimpleConstraint(String regex, String errmsg) without wrapping "/"

_raw: null

_regex: ^([0-9]{1,3}(,[0-9]{1,2})?)?$

_errmsg : myMsg

public String getClientConstraint() : new zul.inp.SimpleConstraint(0,'^([0-9]{1,3}(,[0-9]{1,2})?)?$','myMsg')

The last 2 do NOT work on the front (JS) side, they ALWAYS trigger even when the value match the regex. The first works fine but I don't have my own error message.

So to get it to work I've to use the same way it's used when calling from zul :

  • If I use public SimpleConstraint(String regex) with my error message following the regex and ":"

_raw: /^([0-9]{1,3}(,[0-9]{1,2})?)?$/:myMsg

_regex: ^([0-9]{1,3}(,[0-9]{1,2})?)?$

_errmsg : myMsg

public String getClientConstraint() : '/^([0-9]{1,3}(,[0-9]{1,2})?)?$/:myMsg'

link publish delete flag offensive edit

Comments

I created a ticket at zk, will let you know what answer I get ...

WilliamB ( 2015-12-09 10:14:42 +0800 )edit

No problem, I hope you get it fixed.

chillworld ( 2015-12-09 13:03:41 +0800 )edit
Your answer
Please start posting your answer anonymously - your answer will be saved within the current session and published after you log in or create a new account. Please try to give a substantial answer, for discussions, please use comments and please do remember to vote (after you log in)!

[hide preview]

Question tools

Follow
1 follower

RSS

Stats

Asked: 2015-12-08 11:51:49 +0800

Seen: 55 times

Last updated: Dec 10 '15

Support Options
  • Email Support
  • Training
  • Consulting
  • Outsourcing
Learn More