title: Binding to a ObservableValue<ObservableList> instead of an ObservableList with EasyBind
body: <p>I've got a master/detail panel with <code>ModelItem</code> items. Each <code>ModelItem</code> has a <code>ListProperty&lt;ModelItemDetail&gt;</code>, and each <code>ModelItemDetail</code> has a few <code>StringProperty</code>s. </p>
  
  <p>In the detail panel, I want to show a <code>Label</code> that will have its text bounded to and derived from the properties of each <code>ModelItemDetail</code> of the currently selected <code>ModelItem</code>. The final value may depend on other external properties, such as having a <code>CheckBox</code> on the Detail panel selected (i.e. if the checkbox is selected, the values of <code>bProperty</code> aren't included in the result).</p>
  
  <p>This binding accomplishes what I want, using <code>Bindings.createStringBinding()</code>: </p>
  
  <pre><code>ObservableValue&lt;ModelItem&gt; selectedItemBinding = EasyBind.monadic(mdModel.selectedItemProperty()).orElse(new ModelItem());
  
  // API Label Binding
  apiLabel.textProperty().bind(Bindings.createStringBinding( 
      () -&gt; selectedItemBinding.getValue().getDetails().stream()
          .map(i -&gt; derivedBinding(i.aProperty(), i.bProperty()))
          .map(v-&gt;v.getValue())
          .collect(Collectors.joining(", "))
      , mdModel.selectedItemProperty(), checkBox.selectedProperty()));
  </code></pre>
  
  <p>With for instance: </p>
  
  <pre><code>private ObservableValue&lt;String&gt; derivedBinding(ObservableValue&lt;String&gt; aProp, ObservableValue&lt;String&gt; bProp) {
      return EasyBind.combine(aProp, bProp, checkBox.selectedProperty(), 
              (a, b, s) -&gt; Boolean.TRUE.equals(s) ? new String(a + " &lt;" + b + "&gt;") : a);
  }
  </code></pre>
  
  <p>I recently found out about EasyBind, and I'm trying to replace some API Bindings with it. I can't find a way to express this binding with EasyBind. Apparently, the main problem with my code is that because the selectedItem is a property, I can't use its details as an <code>ObservableList</code>, and I must stick to an <code>ObservableValue&lt;ObservableList&gt;&gt;</code>. This is inconvenient to chain the transformations through <code>EasyBind.map(ObservableList)</code> and <code>EasyBind.combine(ObservableList)</code>, which seem ideal candidates to implement this binding. At some point I've thought of creating a local ListProperty and binding it to the selectedItem's details through a listener on selectedItem, but it just looks too verbose and unclean. </p>
  
  <p>I've tried forcing the EasyBind API like this: </p>
  
  <pre><code>ObservableValue&lt;ObservableList&lt;ModelItemDetail&gt;&gt; ebDetailList = EasyBind.select(selectedItemBinding).selectObject(ModelItem::detailsProperty);
  MonadicObservableValue&lt;ObservableList&lt;ObservableValue&lt;String&gt;&gt;&gt; ebDerivedList = EasyBind.monadic(ebDetailList).map(x-&gt;EasyBind.map(x, i -&gt; derivedBinding(i.aProperty(), i.bProperty())));
  MonadicObservableValue&lt;ObservableValue&lt;String&gt;&gt; ebDerivedValueBinding = ebDerivedList.map(x-&gt;EasyBind.combine(x, stream -&gt; stream.collect(Collectors.joining(", "))));
  easyBindLabel.textProperty().bind(ebDerivedValueBinding.getOrElse(new ReadOnlyStringWrapper("Nothing to see here, move on")));
  </code></pre>
  
  <p>But I've got the feeling the last <code>getOrElse</code> is only getting invoked at initialization time and doesn't update when <code>selectedItem</code> changes.</p>
  
  <p>I've also tried getting the <code>ObservableList</code> right away, but couldn't expect any other thing that an empty list: </p>
  
  <pre><code>ObservableList&lt;ModelItemDetail&gt; ebDetailList = EasyBind.select(selectedItemBinding).selectObject(ModelItem::detailsProperty).get();
  ObservableList&lt;ObservableValue&lt;String&gt;&gt; ebDerivedList = EasyBind.map(ebDetailList, i -&gt; derivedBinding(i.aProperty(), i.bProperty()));
  ObservableValue&lt;String&gt; ebDerivedValueBinding = EasyBind.combine(ebDerivedList, stream -&gt; stream.collect(Collectors.joining(", "))).orElse("Nothing to see here, move on");
  easyBindLabel2.textProperty().bind(ebDerivedValueBinding);
  </code></pre>
  
  <p>I've even tried using <code>EasyBind.subscribe</code> to listen to selectedItem changes and re-bind (not too sure about this but I don't think rebinding would be needed, everything is there to perform the calculations): </p>
  
  <pre><code>EasyBind.subscribe(selectedItemBinding, newValue -&gt; {
      if (newValue != null) {
              ObservableList&lt;ObservableValue&lt;String&gt;&gt; l = 
                  EasyBind.map(newValue.getDetails(), 
                               i -&gt; derivedBinding(i.aProperty(), i.bProperty()));
              easyBindLabelSub.textProperty().bind(
                      EasyBind.combine(l, 
                              strm -&gt; strm.collect(Collectors.joining(", "))
                      ));}});
  </code></pre>
  
  <p>This works partially, actually it's listening to checkbox changes but curiously only to the first change. I don't have a clue why (would be great knowing).
  If I add <em>another</em> <code>EasyBind.Subscribe</code> to subscribe to checkbox.selectedProperty, it works as intended, but this also too verbose and unclean. Same happens if I add an API listener myself to the selectedItemProperty and perform the binding there. </p>
  
  <p>My motivation to use EasyBind to express this binding is precisely get rid of the need to explicitly express dependencies for the binding, and try to simplify it further. All the approaches i've come up with are notably worse than the API one, as much as I'm not fully satisfied with it.</p>
  
  <p>I'm still quite new to JavaFX and I'm trying to wrap my head around this. I want to understand what's happening, and find out if there is a short concise and elegant way to express this Binding with EasyBind. I'm starting to wonder if EasyBind just isn't prepared for this use case (which by the way I don't think is that rare). Probably I am missing something trivial, though. </p>
  
  <p>Here is a MVCE showing a few of the approaches I've tried, and the API Binding working as intended: </p>
  
  <pre><code>package mcve.javafx;
  
  import java.util.*;
  import java.util.stream.*;
  
  import javafx.application.*;
  import javafx.beans.binding.*;
  import javafx.beans.property.*;
  import javafx.beans.value.*;
  import javafx.collections.*;
  import javafx.scene.*;
  import javafx.scene.control.*;
  import javafx.scene.layout.*;
  import javafx.stage.*;
  
  import org.fxmisc.easybind.*;
  import org.fxmisc.easybind.monadic.*;
  
  public class Main extends Application {
      public static void main(String[] args) {
          launch(args);
      }
  
      private CheckBox checkShowMore;
  
      @Override
      public void start(Stage primaryStage) {
          try {
              // Initialize model
              MasterDetailModel mdModel = new MasterDetailModel();
              ObservableList&lt;ModelItem&gt; itemsList = FXCollections.observableArrayList();
              for (int i=0;i&lt;5;i++) { itemsList.add(newModelItem(i)); }
  
              // Master
              ListView&lt;ModelItem&gt; listView = new ListView&lt;ModelItem&gt;();
              listView.setItems(itemsList);
              listView.setPrefHeight(150);
              mdModel.selectedItemProperty().bind(listView.getSelectionModel().selectedItemProperty());
  
              //Detail
              checkShowMore = new CheckBox();
              checkShowMore.setText("Show more details");
              VBox detailVBox = new VBox();           
              Label apiLabel = new Label();
              Label easyBindLabel = new Label();
              Label easyBindLabel2 = new Label();
              Label easyBindLabelSub = new Label();
              Label easyBindLabelLis = new Label();
              detailVBox.getChildren().addAll(
                      checkShowMore, 
                      new TitledPane("API Binding", apiLabel), 
                      new TitledPane("EasyBind Binding", easyBindLabel),
                      new TitledPane("EasyBind Binding 2", easyBindLabel2),
                      new TitledPane("EasyBind Subscribe", easyBindLabelSub),
                      new TitledPane("Listener+EasyBind Approach", easyBindLabelLis)
              );
  
              // Scene
              Scene scene = new Scene(new VBox(listView, detailVBox),400,400);
              primaryStage.setScene(scene);
              primaryStage.setTitle("JavaFX/EasyBind MVCE");
  
              // --------------------------
              // -------- BINDINGS --------
              // --------------------------
              ObservableValue&lt;ModelItem&gt; selectedItemBinding = EasyBind.monadic(mdModel.selectedItemProperty()).orElse(new ModelItem());
  
              // API Label Binding
              apiLabel.textProperty().bind(Bindings.createStringBinding( 
                  () -&gt; selectedItemBinding.getValue().getDetails().stream()
                      .map(i -&gt; derivedBinding(i.aProperty(), i.bProperty()))
                      .map(v-&gt;v.getValue())
                      .collect(Collectors.joining(", "))
                  , mdModel.selectedItemProperty(), checkShowMore.selectedProperty()));
  
              // EasyBind Binding Approach 1
              {
              ObservableValue&lt;ObservableList&lt;ModelItemDetail&gt;&gt; ebDetailList = EasyBind.select(selectedItemBinding).selectObject(ModelItem::detailsProperty);
              MonadicObservableValue&lt;ObservableList&lt;ObservableValue&lt;String&gt;&gt;&gt; ebDerivedList = EasyBind.monadic(ebDetailList).map(x-&gt;EasyBind.map(x, i -&gt; derivedBinding(i.aProperty(), i.bProperty())));
              MonadicObservableValue&lt;ObservableValue&lt;String&gt;&gt; ebDerivedValueBinding = ebDerivedList.map(x-&gt;EasyBind.combine(x, stream -&gt; stream.collect(Collectors.joining(", "))));
              easyBindLabel.textProperty().bind(ebDerivedValueBinding.getOrElse(new ReadOnlyStringWrapper("Nothing to see here, move on")));
              }
  
              // EasyBind Binding Approach 2
              {
              ObservableList&lt;ModelItemDetail&gt; ebDetailList = EasyBind.select(selectedItemBinding).selectObject(ModelItem::detailsProperty).get();
              ObservableList&lt;ObservableValue&lt;String&gt;&gt; ebDerivedList = EasyBind.map(ebDetailList, i -&gt; derivedBinding(i.aProperty(), i.bProperty()));
              ObservableValue&lt;String&gt; ebDerivedValueBinding = EasyBind.combine(ebDerivedList, stream -&gt; stream.collect(Collectors.joining(", "))).orElse("Nothing to see here, move on");
              easyBindLabel2.textProperty().bind(ebDerivedValueBinding);
              }
  
              // Subscribe approach
              EasyBind.subscribe(selectedItemBinding, newValue -&gt; {
                  if (newValue != null) {
                          ObservableList&lt;ObservableValue&lt;String&gt;&gt; l = EasyBind.map(newValue.getDetails(), i -&gt; derivedBinding(i.aProperty(), i.bProperty()));
                          easyBindLabelSub.textProperty().bind(
                                  EasyBind.combine(l, 
                                          strm -&gt; strm.collect(Collectors.joining(", "))
                                  ));
                  }
              });
              //With this it works as intended, but something feels very wrong about this
               /*
              EasyBind.subscribe(checkShowMore.selectedProperty(), newValue -&gt; {
                  if (selectedItemBinding != null) {
                          ObservableList&lt;ObservableValue&lt;String&gt;&gt; l = EasyBind.map(selectedItemBinding.getValue().getDetails(), i -&gt; derivedBinding(i.aProperty(), i.bProperty()));
                          easyBindLabelSub.textProperty().bind(
                                  EasyBind.combine(l, 
                                          strm -&gt; strm.collect(Collectors.joining(", "))
                                  ));
                  }
                  });
              */
  
              // Listener approach
              selectedItemBinding.addListener( (ob, o, n) -&gt; {
                  ObservableList&lt;ModelItemDetail&gt; ebDetailList = n.getDetails();
                  ObservableList&lt;ObservableValue&lt;String&gt;&gt; ebDerivedList = EasyBind.map(ebDetailList, i -&gt; derivedBinding(i.aProperty(), i.bProperty()));
                  ObservableValue&lt;String&gt; ebDerivedValueBinding = EasyBind.combine(ebDerivedList, stream -&gt; stream.collect(Collectors.joining(", "))).orElse("Nothing to see here, move on");
                  easyBindLabelLis.textProperty().bind(ebDerivedValueBinding);                
              });
  
  
  
  
  
              primaryStage.show();
          } catch(Exception e) {
              e.printStackTrace();
          }
      }
  
      private ObservableValue&lt;String&gt; derivedBinding(ObservableValue&lt;String&gt; aProp, ObservableValue&lt;String&gt; bProp) {
          return EasyBind.combine(aProp, bProp, checkShowMore.selectedProperty(), 
                  (a, b, s) -&gt; Boolean.TRUE.equals(s) ? new String(a + " &lt;" + b + "&gt;") : a);
      }   
  
      private ModelItem newModelItem(int number) { 
          ModelItem item = new ModelItem();
          item.itemNumber = number+1;
          for (int i=0;i&lt;2;i++) { 
              ModelItemDetail detail = new ModelItemDetail();
              detail.setA("A" + (i+item.itemNumber));
              detail.setB("B" + (i+item.itemNumber));
              item.getDetails().add(detail);
          }
          return item;
      }
  
      /** GUI Model class */ 
      private static class MasterDetailModel {
          private ObjectProperty&lt;ModelItem&gt; selectedItemProperty = new SimpleObjectProperty&lt;&gt;();
          public ObjectProperty&lt;ModelItem&gt; selectedItemProperty() { return selectedItemProperty; }
          public ModelItem getSelectedItem() { return selectedItemProperty.getValue(); }
          public void setSelectedItem(ModelItem item) { selectedItemProperty.setValue(item); }
      }
  
      /** Domain Model class */
      private static class ModelItem { 
          int itemNumber;
          private ListProperty&lt;ModelItemDetail&gt; detailsProperty = new SimpleListProperty&lt;&gt;(FXCollections.observableArrayList());
          public ListProperty&lt;ModelItemDetail&gt; detailsProperty() { return detailsProperty; }
          public ObservableList&lt;ModelItemDetail&gt; getDetails() { return detailsProperty.getValue(); }
          public void setDetails(List&lt;ModelItemDetail&gt; details) { detailsProperty.setValue(FXCollections.observableList(details)); }
          public String toString() { return "Item " + itemNumber; }
      }
  
      /** Domain Model class */
      private static class ModelItemDetail {
          private StringProperty aProperty = new SimpleStringProperty();
          public StringProperty aProperty() { return aProperty; }
          public String getA() { return aProperty.get(); }
          public void setA(String a) { aProperty.set(a); }
  
          private StringProperty bProperty = new SimpleStringProperty();
          public StringProperty bProperty() { return bProperty; }
          public String getB() { return bProperty.get(); }
          public void setB(String b) { bProperty.set(b); }
      }
  }
  </code></pre>
  
  <p><strong>UPDATE</strong>: I've made some progress. </p>
  
  <p>The following code works fine, but mysteriouysly still keeps listening only to the first change on the CheckBox: </p>
  
  <pre><code>ListProperty&lt;ModelItemDetail&gt; obsList = new SimpleListProperty&lt;&gt;(FXCollections.observableArrayList(i-&gt;new Observable[] { i.aProperty(), i.bProperty(), checkShowMore.selectedProperty()}));
  obsList.bind(selectedItemBinding.flatMap(ModelItem::detailsProperty));
  ObservableList&lt;ModelItemDetail&gt; ebDetailList = obsList; // WHY ??
  ObservableList&lt;ObservableValue&lt;String&gt;&gt; ebDerivedList = EasyBind.map(ebDetailList, i -&gt; derivedBinding(i.aProperty(), i.bProperty()));
  ObservableValue&lt;String&gt; ebDerivedValueBinding = EasyBind.combine(ebDerivedList, stream -&gt; stream.collect(Collectors.joining(", "))).orElse("Nothing to see here, move on");
  labelPlayground.textProperty().bind(ebDerivedValueBinding);
  </code></pre>
  
  <p>Apparently the main reason I was having trouble is because I didn't see how to get an <code>ObservableList</code> from the bound current <code>selectedItem</code> with the EasyBind fluent API. Declaring a local <code>ListProperty</code> and binding it to the selected item's I could take advantage of <code>ListProperty</code> being an <code>ObservableList</code>. I think EasyBind somewhere doesn't follow. Feels like type information is getting lost somewhere. I can't put together all these variables in this last code, and I don't understand why EasyBind.map() will accept <code>ebDetailList</code> in this last code, but won't accept <code>obsList</code>.</p>
  
  <p>So, the question now is, why is this binding listening to CheckBox events only the first time? The extractor in the backing list for the <code>ListProperty</code> doesn't do anything. I guess the <code>obsList.bind()</code> is replacing the backing list with the one in the Model, which has no extractors.</p>