UiBooster icon indicating copy to clipboard operation
UiBooster copied to clipboard

Value Change / Binding change on Enter

Open JoJpeg opened this issue 1 year ago • 4 comments

Hey! I love this Library! It is very nice and easy to work with, Thank you! I was wondering if there is a way to make the value changes in the Form only take place when hitting the Enter key. I feel like this is the expected behavior for me and it leads to a lot of problems when making typos. Am I missing something or is there a bigger reason to not have this functionality?

JoJpeg avatar Sep 08 '24 10:09 JoJpeg

Hi JoJpeg,

thank you very much 😊 Do you have a code snippet for me? I don't really get the problem. The ChangeListener and the data-binding are working with the key-release-event. That means the change will propagade after each key press. Which formelement do you use (text-input, date-picker ...)?

Milchreis avatar Sep 11 '24 04:09 Milchreis

It might just be a personal preference.. I was using the Form.addText() method and the changelListener to display and change numerical values. I was not used to vaules changing before hitting the Return key as i said. Also i needed to parse the values after each keystroke to remove all non-numerical chars. It just seemed like i was using the form for something it was not intended to to. I could solve my problem by building my own custom FormElement using a JSpinner. I think i will also write one that has the value change on Return only..

But still i am curious why you have so many niche form elements like a date or color picker but no numerical spinner element?

JoJpeg avatar Sep 11 '24 08:09 JoJpeg

Ok, I get it. The "return"-key event was not necessary for me, until now. Every change in an input element was the more interesting event, I thought. In that way a validation is possible before the user hits enter.

Please share your JSpinner component in this issue or better in a pull-request. It would be a great addition for the library 😊 UiBooster was an idea years ago and I added necessary features from my real-life tools/projects. A spinner was simply not needed 😅 But it's a great feature-request.

Milchreis avatar Sep 11 '24 19:09 Milchreis

I understand :) was expecting something like that! My current component is not using any of the binding logic and is generally not really fitting your architecture. The "Value changes when pressed Return" functionality comes by default in the spinner.

But for anybody who is interested, this is the code:


public abstract class NumberFieldElement extends FormElement<Double> {

    JSpinner spinner;
    float initialValue;
    float stepSize;
    String innerLabel;

    public NumberFieldElement(String label, float initialValue, float stepSize) {
        //sending no label to the super class since i dont like how much space it takes
        super("");
        this.initialValue = initialValue;
        this.stepSize = stepSize;
        this.innerLabel = label;
    }

    @Override
    public JComponent createComponent(FormElementChangeListener onChange) {

        // create a Horizontal pane that eavenly distributes the elements
        JPanel box = new JPanel();

        // Set the box to span the entire width
        box.setLayout(new BorderLayout());

        spinner = new JSpinner();

        // set the decimal places
        spinner.setModel(new SpinnerNumberModel(initialValue, -9999999999.9, 99999999.9, this.stepSize));

        // set the initial value
        spinner.setValue(initialValue);

        // call the onValueChanged method when the value changes
        spinner.addChangeListener(e -> {
            onValueChanged();
        });

        JLabel label = new JLabel(innerLabel);

        label.setPreferredSize(new Dimension(80, 30));
        label.setSize(new Dimension(80, 30));
        label.setMaximumSize(new Dimension(80, 30));

        // add the label to the left
        box.add(label, BorderLayout.WEST);

        // spacer
        box.add(Box.createHorizontalStrut(10));

        // add the spinner to the right
        box.add(spinner, BorderLayout.EAST);
        return box;
    }

    @Override
    public void setEnabled(boolean enable) {
        spinner.setEnabled(enable);
    }


    @Override
    public Double getValue() {
        Object value = spinner.getValue();
        Double result = null;
        if (value instanceof Float) {
            result = ((Float) value).doubleValue();
            return result;
        } else if (value instanceof Integer) {
            result = ((Integer) value).doubleValue();
            return result;
        } else {
            return (Double) spinner.getValue();
        }
    }

    @Override
    public void setValue(Double value) {
        spinner.setValue(value);
    }

    // abstract method to force the user to implement the onValueChanged method when
    // implementing this class
    public abstract void onValueChanged();

}

The Element is Initialized like this:

   builder.addCustomElement(
                        new NumberFieldElement(fieldName, initialValue, isInteger ? 1f : 0.01f) {
                            @Override
                            public void onValueChanged() {
                                System.out.println("Value changed to: " + getValue());
                                myMethodToChangeData(object, fieldName, getValue().toString(), fieldType);
                            }
                        }).setID(fieldName);

JoJpeg avatar Sep 11 '24 21:09 JoJpeg

Hi @JoJpeg

thank you very much for sharing your code. Already this issue is more than a year old, but today I integrated your code. In the next version UiBooster will support number-fields, especially of your work 👍

Integrated with: 9c11489fda24a80bd3b87be003af7b87cef803e1

Milchreis avatar Nov 07 '25 21:11 Milchreis