2

I have a controller like this:

public class ItemController {
    @FXML TextField name;
    @FXML TextField description;
    private City city = null;

    @FXML public void initialize () {
        name.textProperty().bind(city.nameProperty());
        description.textProperty().bind(city.descriptionProperty());
    }

    public void searchById(int idCity) {
           //get a city by its id, it returns null if not found
           city = Backend.getCity(idCity);
    }
}

As you see city is initially assigned to null, and searchById assigns it to a new value, I want to create a bind to properties of city when it has a valid value but it's not then set the text properties to empty (perhaps unbinding the fields but I'm not sure) and disable the fields, but I don't have a good idea how to do it, thanks in advance for any help.

user2005494
  • 189
  • 1
  • 12
  • Your binding wouldn't work even if `city` wasn't null: when you change `city`, the text field would still be bound to the old city's name. You need to make `city` and observable property and probably use a third party binding library such as [EasyBind](https://github.com/TomasMikula/EasyBind) or the binding functionality in [ReactFX](https://github.com/TomasMikula/ReactFX). – James_D Jan 26 '17 at 23:00

1 Answers1

3

You need the binding to change not only if the name changes, but also if the city changes. For this to happen, city itself must be observable.

// private City city = null;
private ObjectProperty<City> city = new SimpleObjectProperty<>();

Now your text field has to be bound to a "property of a property". There is some limited API for this in the standard libraries, but it is not well written and handles null values extremely badly. I recommend you use a third party library for this kind of functionality. ReactFX has this functionality built in, and you can do

@FXML public void initialize () {
    name.textProperty().bind(Val.flatMap(city, City::nameProperty).orElseConst(""));
    name.disableProperty().bind(city.isNull());

    // ...
}

For bidirectional binding you can do

name.textProperty().bindBidirectional(Val.selectVar(city, City::nameProperty));
James_D
  • 201,275
  • 16
  • 291
  • 322
  • I'm not understand very well what exactly does flatMap, but yes, it works like a charm, just a last question, how could create a bind to a nested property like city.getCountry().getName() ? – user2005494 Jan 27 '17 at 02:04
  • `Val.flatMap(city, City::countryProperty).flatMap(Country::nameProperty).orElseConst("")`. – James_D Jan 27 '17 at 02:21
  • What is `Val`? Is it a class or an object? Where is it defined? I don't see it in the javadocs for ReactFX – skrilmps Jul 11 '17 at 21:41
  • 1
    It's a class in the ReactFX framework. May only be in the latest development release. – James_D Jul 11 '17 at 22:04