6 Replies Latest reply on Apr 30, 2013 9:28 AM by jfuerth

    Binding ValueListBox with <select/> html tag

    jmbarone

      Hi ... i'm trying to do a <select/> binding to a ValueListBox.

      The project is using Errai UI and Errai Binding.

      Bindings of String properties with ListBox and <select/> are working perfect ... the same with basic properties (int, String, ...)

       

      But when i try to bind a value with the binder (i do a setModel on the binder) i have a ClassCastException when Errai set the value in the ValueListBox.

       

      java.lang.ClassCastException: java.lang.String cannot be cast to xxxxxx (xxxxxx it's the value java class)

       

       

      It seems that internally the binder try to do a setValue on the ValueListBox with a String type, not with an object of the value class, but i correctly configured the generics part of the ValueListBox, the  Renderer .... :-(

       

      Thanks for any guide about how to resolve this issue.

        • 1. Re: Binding ValueListBox with <select/> html tag
          jfuerth

          Hi Jose,

           

          I should be able to help you get to the bottom of this if you can provide an example class that demonstrates the problem. Would you please respond with a complete @Templated class (and its corresponding .html file) that exhibits this problem?

           

          Thanks,

          Jonathan

          • 2. Re: Binding ValueListBox with <select/> html tag
            jmbarone

            Ok Jonathan ... i will try to explain the problem, but let me say that it's a simple and plain example.

             

            Here goes the html view:

            <!DOCTYPE html>

            <html>

            <form>

                      <label for="tipo">Tipo</label>

                      <select data-field="tipoMateriaPrima" id="tipo"></select><br>

             

             

                      <label for="nombre">Nombre</label>

                      <input id="nombre" type="text" data-field="nombre"><br>

             

                      <label for="cantidad">Cantidad</label>

                      <input data-field="cantidad" id="cantidad" type="number">

             

                      <select data-field="unidadMedida" id="unidadMedida"></select><br>

             

                      <label for="lote">Lote</label>

                      <input data-field="nroLote" id="nroLote" type="number"><br>

             

             

                      <label for="proveedor">Proveedor</label>

                      <select data-field="proveedor" id="proveedor"></select>

             

             

                      <label for="loteProveedor">Lote del proveedor</label>

                      <input data-field="loteProveedor" id="loteProveedor"><br>

             

             

                      <label for="factura">Factura</label>

                      <input data-field="factura" id="factura"><br>

             

             

                      <label for="tercerizacion">Tercerizacion</label>

                      <select data-field="tercerizacion" id="tercerizacion"></select><br>

             

             

                      <button data-field="submit">Ok</button>

            </form>

            </html>

             

            It´s a pretty simple html, with two select´s, on fields "tercerizacion" and "proveedor" (we're talking a little spanish here )

             

            Ok, then the "controller" class:

             

            @Templated("MateriaPrimaView.html")

            public class MateriaPrimaController extends Composite {

                      Logger logger = Logger.getLogger("MateriaPrimaView");

             

                      @Inject

                      Event<MateriaPrima> event;

                      @Inject

                      @AutoBound

                      private DataBinder<MateriaPrima> dataBinder;

             

                      @Inject

                      @DataField

                      @Bound

                      private ListBox tipoMateriaPrima;

             

             

                      @Inject

                      @DataField

                      @Bound

                      private TextBox nombre;

             

                      @Inject

                      @DataField

                      @Bound

                      private TextBox cantidad;

             

                      @Inject

                      @DataField

                      @Bound

                      private ListBox unidadMedida;

             

             

                      @Inject

                      @DataField

                      private TextBox nroLote;

             

                      @Inject

                      @DataField

                      @Bound

                      private ListBox proveedor;

             

             

                      @Inject

                      @DataField

                      @Bound

                      private TextBox loteProveedor;

             

             

                      @Inject

                      @DataField

                      @Bound

                      private TextBox factura;

             

             

                      @Inject

                      @DataField

                      @Bound

                      private ListBox tercerizacion;

             

             

                      @Inject

                      @DataField

                      private Button submit;

             

                      public MateriaPrimaController(){

              }

             

                      }

             

                      @PostConstruct

                      public void init(){

                                tipoMateriaPrima.addItem("ITEM_1");

                                tipoMateriaPrima.addItem("ITEM_2");

                      }

             

                      public void setModelInstance(MateriaPrima mp){

                                dataBinder.setModel(mp, InitialState.FROM_MODEL);

                                dataBinder.getModel();

                      }

             

                      @EventHandler("submit")

                      private void submit(ClickEvent e){

                                logger.info("submit");

                                event.fire(dataBinder.getModel());

                      }

            }

             

             

            And finally the "App" class:

             

            @EntryPoint

            public class App {

                      @Inject

                      private MateriaPrimaController mpc;

             

                      @PostConstruct

                      public void init(){

                                MateriaPrima mp = new MateriaPrima("Materia 1", 5,

                                                    UNIDAD_MEDIDA.Kg, new TipoMateriaPrima("ITEM_2"),

                                                    new Tercerizacion("Tercerizacion 1"));

             

             

                                mp.setLoteProveedor("345RT");

                                mp.setNroLote(6734);

                                mp.setFactura("A3490");

                                mp.setProveedor(new Proveedor("Proveedor1"));

                                mpv.setModelInstance(mp);

             

                                RootPanel.get().add(mpc);

                  }

            }

             

             

            It´s really simply, i want to bound a ComboBox with a list of values, it´s an "all time" feature for programmers.

            I think ... is this the right way with Errai?

             

            Also, continue the good work with the framework, it's awesome.

            Thanks.

            • 3. Re: Binding ValueListBox with <select/> html tag
              jfuerth

              Hi Jose,

               

              Thanks for taking the time to communicate these details! The real problem is that ListBox doesn't implement HasValue, so Errai's Data Binding feature doesn't know how to set/get the selected item from the combo box, and it also doesn't know how to observe it for changes to the selection.

               

              I've worked with your code and found a clean solution to the problem: you can subclass ListBox and implement HasValue<String> like this:

               

              import com.google.gwt.event.dom.client.ChangeEvent;
              import com.google.gwt.event.dom.client.ChangeHandler;
              import com.google.gwt.event.logical.shared.ValueChangeEvent;
              import com.google.gwt.event.logical.shared.ValueChangeHandler;
              import com.google.gwt.event.shared.HandlerRegistration;
              import com.google.gwt.user.client.ui.HasValue;
              import com.google.gwt.user.client.ui.ListBox;
              
              public class BindableListBox extends ListBox implements HasValue<String> {
              
                public BindableListBox() {
                  addChangeHandler(new ChangeHandler() {
                    @Override
                    public void onChange(ChangeEvent event) {
                      ValueChangeEvent.fire(BindableListBox.this, getValue());
                    }
                  });
                }
              
                @Override
                public HandlerRegistration addValueChangeHandler(ValueChangeHandler<String> handler) {
                  return addHandler(handler, ValueChangeEvent.getType());
                }
              
                @Override
                public String getValue() {
                  return getItemText(getSelectedIndex());
                }
              
                @Override
                public void setValue(String value) {
                  setValue(value, true);
                }
              
                @Override
                public void setValue(String value, boolean fireEvents) {
                  int foundIndex = -1;
                  for (int i = 0; i < getItemCount(); i++) {
                    if (value.equals(getItemText(i))) {
                      foundIndex = i;
                      break;
                    }
                  }
              
                  if (foundIndex == -1) {
                    // didn't find a match. we can add the value.
                    addItem(value);
                    setSelectedIndex(getItemCount() - 1);
                  }
              
                  if (fireEvents) {
                    ValueChangeEvent.fire(this, value);
                  }
                }
              
              }
              

              Once you have this BindableListBox, just change the ListBox injection points in MateriaPrimaController to BindableListBox, like this:

               

                        @Inject
                        @DataField
                        @Bound
                        private BindableListBox proveedor;
              

               

              Hope that helps!

               

              -Jonathan

              • 4. Re: Binding ValueListBox with <select/> html tag
                jmbarone

                Jonathan: thanks for the response.

                 

                With ListBox it works directly ... but i want to work with the values, not with a string representation of them.

                I mean, it will be more simply and natural to add the values to a gwt component and then ask for the selected value obtained from the user, without the boilerplate of what string is what value in my model.

                 

                More precisely ... i want to add the Proveedor values to a list and then obtain which Proveedor was selected for the user ... simple.

                It's different to add the names to the list and then obtain the selected name and "calculate" wich Proveedor corresponds with that name ... appears more procedural against an object model.

                 

                What do you think?

                 

                Thanks

                • 5. Re: Binding ValueListBox with <select/> html tag
                  jmbarone

                  Well ... i have it working now

                   

                  How? ... simple, change it to 2.3.0.CR1 version of Errai.

                  Now i can use the ValueListBox binded to <select /> html tags and using objects of my domain, not strings.

                  Other thing that matters is to create the equals and hash on the domain classes, without that the combo boxes always appends new values.

                   

                  Thanks and i hope this can help someone out there.

                  • 6. Re: Binding ValueListBox with <select/> html tag
                    jfuerth

                    Oh, your solution is even better. I didn't know about ValueListBox!

                     

                    Thanks for the tip!

                     

                    -Jonathan