Search code examples
javafxcombobox

Why does the child ComboBox performs dual action whenever I change the selected item from its parent ComboBox.?


I have this nested Combobox, that whenever I selected something from the parent Combobox, the items from the child Combobox changes. At first try, it performs exactly what I want it to be. But when I change the selected value of the parent Combobox, the child Combobox double its action.

For example, when I selected the child Combobox, it will display "Me". But whenever I change the parent and then select the child again, it will display "Me" twice, which is supposed to be only once.

Here is my code.

cdata = ComboBoxCaller.getCityMun("PH-NCR");
cmbCit.setItems(cdata);
cmbCit.setConverter(new StringConverter<City_Municipality>() {
    @Override
    public String toString(City_Municipality object) {
        return object.getCityName();
    }

    @Override
    public City_Municipality fromString(String string) {
        return cmbCit.getItems().stream().filter(ap -> ap.getCityName().equals(string)).findFirst().orElse(null);
    }
});

pdata = ComboBoxCaller.getProvince();
cmbProv.setItems(pdata);
cmbProv.setConverter(new StringConverter<Province>() {
    @Override
    public String toString(Province object) {
        return object.getPname();
    }

    @Override
    public Province fromString(String string) {
        return cmbProv.getItems().stream().filter(ap -> ap.getPname().equals(string)).findFirst().orElse(null);
    }
});

cmbProv.valueProperty().addListener((ObservableValue<? extends Province> obs, Province oldval, Province newval) -> {
    if (newval != null) {
        System.out.println("Selected: " + newval.getPname() + ". ID: " + newval.getPcode());
        prov_nm = newval.getPname();

        // Setting up list of Cities and Municipality
        cdata = ComboBoxCaller.getCityMun(newval.getPcode());
        cmbCit.setItems(cdata);
        cmbCit.setConverter(new StringConverter<City_Municipality>() {
            @Override
            public String toString(City_Municipality object) {
                return object.getCityName();
            }

            @Override
            public City_Municipality fromString(String string) {
                return cmbCit.getItems().stream().filter(ap -> ap.getCityName().equals(string)).findFirst().orElse(null);
            }
        });

        // this is where the bug/error occurs
        cmbCit.valueProperty().addListener((ObservableValue<? extends City_Municipality> option, City_Municipality old, City_Municipality newVal) -> {
            if (newVal != null) {
                city_nm = newVal.getCityName();
                cit_id = newVal.getPkCit();
                System.out.println("City: " + city_nm + " City ID: " + cit_id);
                isDisable(false);   // disable

                //Setting up list of Sub-Municipalities
                smdata = ComboBoxCaller.getSubMun(newVal.getPkCit());
                cmbSubMun.setItems(smdata);
                cmbSubMun.setConverter(new StringConverter<Sub_Municipality>() {
                    @Override
                    public String toString(Sub_Municipality object) {
                        return object.getSub_mun();
                    }

                    @Override
                    public Sub_Municipality fromString(String string) {
                        return cmbSubMun.getItems().stream().filter(ap -> ap.getSub_mun().equals(string)).findFirst().orElse(null);
                    }
                });

                cmbSubMun.valueProperty().addListener((ObservableValue<? extends Sub_Municipality> opt, Sub_Municipality od, Sub_Municipality nw) -> {
                    if (nw != null) {
                        sub_vil = nw.getSub_mun();
                        subMun = nw.getSub_mun();
                    }
                });

                //Setting up list of Subdivisions and Village
                sdata = ComboBoxCaller.getSubVil(newVal.getPkCit());
                cmbSub.setItems(sdata);
                cmbSub.setConverter(new StringConverter<Subdivision_Village>() {
                    @Override
                    public String toString(Subdivision_Village object) {
                        return object.getSub_vil();
                    }

                    @Override
                    public Subdivision_Village fromString(String string) {
                        return cmbSub.getItems().stream().filter(ap -> ap.getSub_vil().equals(string)).findFirst().orElse(null);
                    }
                });

                cmbSub.valueProperty().addListener((ObservableValue<? extends Subdivision_Village> opt, Subdivision_Village od, Subdivision_Village nw) -> {
                    if (nw != null) {
                        sub_vil = nw.getSub_vil();
                    }
                });
            } else {
                isDisable(true);
            }
        });
    }
});

the bug/error, occurred on cmbCit, that whenever I change the selected value of cmbProv, the items of cmbCit changes BUT, whenever I select an item from cmbCit, it will perform twice.


Solution

  • I see that you are adding a listener for cmbCit.valueProperty() inside another listener cmbProv.valueProperty()). Be very careful with this kind of implementation because it may raise problems : in your case, the more you will select an item in cmbProv, the more you will collect listeners for cmbCit.valueProperty(). You have to remove your listener each time you invoke cmbCit.valueProperty() to make sure you won't have your procedure executed several times at once.