I sent a pull request your way.
The key to answer this question is to have two Observables in your view model. One that represents the programatic state of each cell (the stuff that the user doesn't input) and one that represents the user input state of each cell. You connect the data from these two Observables using some sort of ID value (I use UUID.) So for your specific example, the view model for the collection should look like this:
typealias CellID = UUID
struct StaticCellState {
let id: CellID
let placeholder: String
}
struct CollectionViewModel {
let cells: Observable<[StaticCellState]>
let cellStates: Observable<[CellID: String]>
}
The cells
observable contains the placeholder and cell ID. This is the data that the cell uses when it is configured and doesn't change for the life of that configuration (It might change if the cell is reused.) It is only updated if you want to add/remove a cell or change the placeholder value of a particular cell.
The cellStates
observable contains the latest user input values and is updated every time the user types into one of the cells' text fields.
Then you configure your cells by passing in the information for that cell from both observables:
let dataSource = RxCollectionViewSectionedReloadDataSource<SectionOfCustomData>(
configureCell: { dataSource, collectionView, indexPath, item in
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as? SomeCell else { return UICollectionViewCell() }
let output = cell.configure(with: item, initial: viewModel.cellStates.map { $0[item.id]! })
output
.bind(to: itemEdit)
.disposed(by: cell.disposeBag)
return cell
})