JavaFX TableView and ObservableList - How to auto-update the table?
<p>I know questions similar to this have been asked, and on different dates, but I'll put an SSCCE in here and try to ask this simply.</p>

<p>I would like to be able to update the data model, and have any views upon it automatically update, such that any caller updating the model is not aware of whatever views there presently are. This is what I learned/tried so far, and without calling <code>TableView.refresh()</code> it does not update.  What am I missing?</p>

<p>main.java:</p>

<pre><code>package application;

import javafx.application.Application;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Pos;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.VBox;

public class Main extends Application {
    @Override
    public void start(Stage stage) {

        // data
        ObservableList&lt;Crew&gt; data = FXCollections.observableArrayList();
        data.addAll(new Crew(1, "A"), new Crew(2, "B"));

        // table
        TableColumn&lt;Crew, Integer&gt; crewIdCol = new TableColumn&lt;Crew, Integer&gt;("Crew ID");
        crewIdCol.setCellValueFactory(new PropertyValueFactory&lt;Crew, Integer&gt;("crewId"));
        crewIdCol.setMinWidth(120);
        TableColumn&lt;Crew, String&gt; crewNameCol = new TableColumn&lt;Crew, String&gt;("Crew Name");
        crewNameCol.setCellValueFactory(new PropertyValueFactory&lt;Crew, String&gt;("crewName"));
        crewNameCol.setMinWidth(180);
        TableView&lt;Crew&gt; table = new TableView&lt;Crew&gt;(data);
        table.getColumns().addAll(crewIdCol, crewNameCol);
        table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);

        // button
        Button button = new Button(" test ");
        button.setOnAction(ae -&gt; {
            // test
            StringProperty nameProp = data.get(0).crewName();
            if(nameProp.get().equals("A")) {
                data.get(0).setCrewName("foo");
                // table.refresh();
                System.out.println("foo");
            } else {
                data.get(0).setCrewName("A");
                // table.refresh();
                System.out.println("A");
            }
        });

        VBox box = new VBox(10);
        box.setAlignment(Pos.CENTER);;
        box.getChildren().addAll(table, button); 
        Scene scene = new Scene(box);
        stage.setScene(scene);
        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }

}
</code></pre>

<p>Crew.java</p>

<pre><code>package application;

import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;

public class Crew {
    private final IntegerProperty crewId = new SimpleIntegerProperty();
    private final StringProperty crewName = new SimpleStringProperty();

    Crew(int id, String name) {
        crewId.set(id);
        crewName.set(name);
    }

    public IntegerProperty crewId() { return crewId; }
    public final int getCrewId() { return crewId.get(); }
    public final void setCrewId(int id) { crewId.set(id); }

    public StringProperty crewName() { return crewName; }
    public final String getCrewName() { return crewName.get(); }
    public final void setCrewName(String name) { crewName.set(name); }

}
</code></pre>