Reputation: 1257
I have just started working with RxSwift and facing some challenges. I have created tableview with multiple section and able to tap and get details. However if I try to delete any particular cell, its not working. I am not sure what I am doing wrong in RxSwift. Below is my code.
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let dataSource = RxTableViewSectionedReloadDataSource<SectionModel<String, User>>(
configureCell: { (_, tv, indexPath, element) in
let cell = tv.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
cell.textLabel?.text = string
cell.textLabel?.numberOfLines = 0
return cell
},
titleForHeaderInSection: { dataSource, sectionIndex in
return dataSource[sectionIndex].model
}
)
dataSource.canEditRowAtIndexPath = { dataSource, indexPath in
return true
}
viewModel.getUsers()
.bind(to: tableView.rx.items(dataSource: dataSource))
.disposed(by: disposeBag)
tableView.rx
.itemSelected
.map { indexPath in
return (indexPath, dataSource[indexPath])
}
.subscribe(onNext: { pair in
print("Tapped \(pair.1) @ \(pair.0)")
})
.disposed(by: disposeBag)
tableView.rx.itemDeleted
.subscribe{
print($0)
}
.disposed(by: disposeBag)
tableView.rx
.setDelegate(self)
.disposed(by: disposeBag)
}
Upvotes: 3
Views: 6816
Reputation: 14780
tableView.rx.itemDeleted
triggers an event containing the indexPath
, where the delete action has happened. The change on your data should be handled by you. You are not getting any update, because you are not changing anything, you are just printing the indexPath
out.
Since you are using a viewModel.getUsers()
which returns you an Observable<[SectionModel<String, User>]>
judging from your code. You also should introduce a method on the viewModel
which will be used to remove an item at a specific indexPath
.
In order to achieve that, you need to have a storage of your elements in a BehaviorSubject
. This will hold the current value of the data, and when updated it will emit the new data to the ones which subscribed to it.
let sectionListSubject = BehaviorSubject(value: [SectionModel<String, User>]())
When you initialize your viewModel
, you need to populate this subject with data doing so:
sectionListSubject.onNext([
SectionModel(model: "First section", items: [
User(),
User(),
User()
]),
SectionModel(model: "Second section", items: [
User(),
User(),
User()
])
])
Then your getUsers()
method should look like:
func getUsers() -> Observable<[SectionModel<String, User>]> {
return sectionListSubject.asObservable()
}
Last step on your viewModel
, would be to implement the removeItem(at:)
func removeItem(at indexPath: IndexPath) {
guard var sections = try? sectionListSubject.value() else { return }
// Get the current section from the indexPath
var currentSection = sections[indexPath.section]
// Remove the item from the section at the specified indexPath
currentSection.items.remove(at: indexPath.row)
// Update the section on section list
sections[indexPath.section] = currentSection
// Inform your subject with the new changes
sectionListSubject.onNext(sections)
}
Now on the codebase you have you just need to change:
tableView.rx.itemDeleted
.subscribe(onNext: { self.viewModel.removeItem(at: $0) })
.disposed(by: disposeBag)
Deleting should now work.
Upvotes: 7