Getting the selected value of a <vaadin-combo-box> into Java using Template

I have a problem getting the value of the selected item in a element.
I am working on Vaadin 10 using a JAVA/HTML TemplateModel and the vaadin-combo-box is a element in the html code.

I can set the values in the combo box from the java side using the SetItems() method.

I can select an item in the drop down list and the valueChange() method fires on the Server side but I cannot seem to get the value of the selected value back on the server side.

I think I am not referencing the correct property.

My html looks like this …

<vaadin-combo-box id="paystates" value="{{userInput}}" label="Payment Status" on-value-changed="valueChange" items="{{paystateitems}}"></vaadin-combo-box>

My Java Code has the following …

   public interface PaymentsModel extends TemplateModel {
        void setPayments(List<Payment> payments);
        String getUserInput();
    }

   @Id("paystates")
   private ComboBox<String> paystates;
   List<String> paystateitems = new ArrayList<String>();
   .....
   paystates.setItems(paystateitems);
	
   @EventHandler
    private void valueChange() {
        mLogger.info("Value of paystatus from event handler = ", this.getModel().getUserInput());
    }	

The value from the getUserInput() is always blank.

Grateful for any hint as I have spent a lot of time trying to get this to work and I think I am missing something very basic.

I’m not sure if I understand your needs. Why do you want to define the value change listener in the template and not in the java code?

You could set the value change listener of your ComboBox in the java code like this

paystates.addValueChangeListener(event -> {
	mLogger.info("Value of paystatus from event handler = ", event.getValue());
});

Assuming I am wrong and you indeed need to do it your way: Where is the implementation of getUserInput()? I am not very accustomed with TemplateModels, but I guess either your template or your view needs to implement getUserInput() somewhere - defining it’s existence in the PaymentsModel interface is not enough.

Kaspar,

Thanks for coming back to me. I have tried it as you suggested as well and I get a the same result.
That was the way I tried first but that does not work either. The value is always blank even though the value change listener is fired whenever I select an item in the browser.

I tried to follow this example

https://vaadin.com/forum/thread/17277221/dropdown-comboxbo-two-way-binding-to-a-viewmodel

and this led me to the approach I posted initially.

I think if you follow the examples in the TemplateModel docs it doesn’t mention providing an implementation for the Model methods.

https://vaadin.com/docs/v14/flow/polymer-templates/tutorial-template-basic.html#model

I think the TemplateModel autpmatically generates an implementation based on the property name so for example if you have a “greeting” variable in the html a "SetGreeting() method in the model will set that value. You don’t need to provide an implementation for SetGreeting(). I am very new to this and I may be totally out in left field here on that but that is what I infer from the documentation.

You are right you don’t need to provide implementations there.

Is the comboBox in your code actually of type String or did you change that for posting it here? If it’s a ComboBox with one of your own classes as type, then have you checked that the toString() method of said class does not return an empty string? (or see in debugger if event.getValue() is indeed null / empty String)

Oh and just now I also noticed another possibility:
In the documentation that you linked (template basics) they use a paper-input which I believe is basically a TextField. It is possible that the usage of a two-way binding ({{userInput}}) does not work the same for ComboBoxes as they do for TextFields.

Here is where my guesses end, and I hope that you find further help from official Vaadin devs here if none of my guesses are true.

Edit: I hope this documentation explains it a bit better than I can (I still don’t understand 100% of it but I think this is indeed your problem) - https://vaadin.com/docs/v14/flow/polymer-templates/tutorial-template-bindings.html#two-way-binding

Kaspar,

Yes, the ComboBox is of type ComboBox and I just set a couple of string values in the list

    private ComboBox<String> paystates;
	List<String> paystateitems = new ArrayList<String>();
    paystateitems.add("Authorised");
    paystateitems.add("Not Authorised");
    paystateitems.add("All");
    paystates.setItems(paystateitems);

I know the example is different and I think you are right - the ComboBox must work differently and I am just not setting it up right.

Thank you for your help,

John.

Just to add a little more to the discussion - I can see on the browser console log the following messages …

If I select the 2nd item in the list - I get this message

Sending xhr message to server: {"csrfToken":"ce3c712c-1760-41e7-aca1-3eb05bc17f6c","rpc":

[{"type":"publishedEventHandler","node":431,"templateEventMethodName":"valueChange","templateEventMethodArgs":[]
},

{"type":"mSync","node":4,"feature":1,"property":"selectedItem","value":{"key":"2","label":"Not Authorised"}},

{"type":"mSync","node":4,"feature":1,"property":"value","value":"2"},

{"type":"mSync","node":4,"feature":1,"property":"opened","value":false}],"syncId":2,"clientId":2}

If I select the first item in the list - I get this message

Sending xhr message to server: {"csrfToken":"ce3c712c-1760-41e7-aca1-3eb05bc17f6c","rpc":

[{"type":"publishedEventHandler","node":431,"templateEventMethodName":"valueChange","templateEventMethodArgs":[]
},

{"type":"mSync","node":4,"feature":1,"property":"selectedItem","value":{"key":"1","label":"Authorised"}},

{"type":"mSync","node":4,"feature":1,"property":"value","value":"1"},

{"type":"mSync","node":4,"feature":1,"property":"opened","value":false}],"syncId":4,"clientId":4}

So there is a property called “selectedItem” with the information I want and it is being sent to the server but I don’t know how to get at it on the Server side.

I got this to work finally but I don’t think it is the best/only way to do it.

The details come back as part of a property change listener and the details are returned in a JSON object.

I used JSON to get the label value which is what I was looking for.

What am I missing in terms of the use of TemplateModels in two-way data binding as I think this can’t be the best way to do this.

        paystates.getElement().addPropertyChangeListener("selectedItem", event -> {
            mLogger.info("Selected Item is set to: " + event.getValue());
            mLogger.info("Property Name = " + event.getPropertyName());
            mLogger.info("Source = " + event.getSource());
            final String l_json = event.getValue().toString();
            try {
                mLogger.info("JSON Response to Request: " + l_json);
                final JsonReader l_jsonReader = Json.createReader(new StringReader(l_json));
                JsonObject Response = l_jsonReader.readObject();
                l_jsonReader.close();
                mLogger.info("Selected Item = " + Response.getString("label"));
            } catch (Exception e) {
                mLogger.error("Exception access the Property Change event" + e.getMessage());
            }

        });

John,

For forms I generally map all components using the @Id attribute. It’s possible that using a model or just the element attributes directly is more efficient in terms of memory and or performance, but I have not noticed any significant degradation when using @Id vs. not.

When I map a component using @Id, I don’t declare anything for that component in the model. So most of my forms have a completely empty model.

I don’t recall having seen any warnings about using both @Id and model to interact with a component, but my suggestion would be to use one or the other, but not both at the same time.