I'm trying to create editable cells using Oracle poor tutorial. I figured out that their EditCell class only updates when I click on the same row I currently edit or outside any row. In case when I click on another row, edit is cancelled. Here is the link to this tutorial and on the end of it you can find EditCell class, but it's not the point of this question: 
https://docs.oracle.com/javase/8/javafx/user-interface-tutorial/table-view.htm
This class creates TextField for edit purposes. Clicking on another row launches cancel() method. And there is this code line:
setText((String( getItem());
that blocks edit. I replaced it with:
setText((String) textField.getText());
and edit works now. But after editing this cell again old value is loaded to TextField. I guess that ObservableList is not updated after first edit.
Here is FXML code:
<GridPane fx:controller="sample.Controller"
      xmlns:fx="http://javafx.com/fxml" alignment="center" hgap="10" vgap="10">
    <TableView GridPane.columnIndex="0" GridPane.rowIndex="1" items="${controller.data}" editable="true">
        <columns>
            <TableColumn fx:id="colName" text="name">
                <cellValueFactory>
                    <PropertyValueFactory property="Name"/>
                </cellValueFactory>
            </TableColumn>
            <TableColumn fx:id="colSurname" text="surname">
                <cellValueFactory>
                    <PropertyValueFactory property="Surname"/>
                </cellValueFactory>
            </TableColumn>
        </columns>
    </TableView>
</GridPane>
In controller I declare ObservableList:
public class Controller {
    @FXML
    private TableColumn<Person, String> colName;
    @FXML
    private TableColumn<Person, String> colSurname;
    @FXML
    private ObservableList<Person> data;
    public Controller(){
        data = FXCollections.observableArrayList(
                new Person("John", "S."),
                new Person("Jane", "S.")
        );
    }
    public TableColumn<Person, String> getColName() {
        return colName;
    }
    public void setColName(TableColumn<Person, String> colName) {
        this.colName = colName;
    }
    public TableColumn<Person, String> getColSurname() {
        return colSurname;
    }
    public void setColSurname(TableColumn<Person, String> colSurname) {
        this.colSurname = colSurname;
    }
    public ObservableList<Person> getData() {
        return data;
    }
    public void setData(ObservableList<Person> data) {
        this.data = data;
    }
}
Person.java code:
public class Person {
    private final SimpleStringProperty name;
    private final SimpleStringProperty surname;
    public Person(String name, String surname){
        this.name = new SimpleStringProperty(name);
        this.surname = new SimpleStringProperty(surname);
    }
    public String getName() {
        return name.get();
    }
    public SimpleStringProperty nameProperty() {
        return name;
    }
    public void setName(String name) {
        this.name.set(name);
    }
    public String getSurname() {
        return surname.get();
    }
    public SimpleStringProperty surnameProperty() {
        return surname;
    }
    public void setSurname(String surname) {
        this.surname.set(surname);
    }
}
In Main I declare controller and editable column:
public class Main extends Application {
    @Override
    public void start(Stage primaryStage) throws Exception {
        FXMLLoader loader = new FXMLLoader(getClass().getResource("sample.fxml"));
        Parent root = (Parent) loader.load();
        primaryStage.setScene(new Scene(root, 300, 275));
        Controller controller = loader.getController();
        TableColumn<Person, String> colName = controller.getColName();
        Callback<TableColumn<Person, String>, TableCell<Person, String>> cellFactory =
            (TableColumn<Person, String> p) -> new sample.EditCell();
        colName.setCellFactory(cellFactory);
        colName.setOnEditCommit(
                (TableColumn.CellEditEvent<Person, String> t) -> {
                    ((Person) t.getTableView().getItems().get(
                            t.getTablePosition().getRow())
                    ).setName(t.getNewValue());
                });
        primaryStage.show();
    }
    public static void main(String[] args) {
       launch(args);
    }
}
Do I need bind cell with ObservableList? Or refresh it? How to update data to have TextField always filled with actual value?
Here is whole EditCell class:
class EditCell extends TableCell<Person, String> {
    private TextField textField;
    public EditCell() {
    }
    @Override
    public void startEdit() {
        if (!isEmpty()) {
            super.startEdit();
            createTextField();
            setText(null);
            setGraphic(textField);
            textField.selectAll();
        }
    }
    @Override
    public void cancelEdit() {
        super.cancelEdit();
        setText((String) getItem());
        //setText((String) textField.getText());
        //This line updates cell, but textField keeps old value after next edit.
        setGraphic(null);
    }
    @Override
    public void updateItem(String item, boolean empty) {
        super.updateItem(item, empty);
        if (empty) {
            setText(null);
            setGraphic(null);
        } else {
            if (isEditing()) {
                if (textField != null) {
                    textField.setText(getString());
                }
                setText(null);
                setGraphic(textField);
            } else {
                setText(getString());
                setGraphic(null);
            }
        }
    }
    private void createTextField() {
        textField = new TextField(getString());
        textField.setMinWidth(this.getWidth() - this.getGraphicTextGap() * 2);
        textField.focusedProperty().addListener(
                (ObservableValue<? extends Boolean> arg0,
                 Boolean arg1, Boolean arg2) -> {
                    if (!arg2) {
                        commitEdit(textField.getText());
                    }
                });
    }
    private String getString() {
        return getItem() == null ? "" : getItem().toString();
    }
}