Let say we have array of InvoiceDataModel
private let invoices Variable<[InvoiceDataModel]> = Variable([])
class InvoiceDataModel {
let id: Variable<Int>
var entity: Variable<InvoiceDto>
var isSelected: Variable<Bool>
}
On tap on checkbox I am changing value of isSelected. What I want to achieve is to react on isSelect change to:
var amount: Double
) Is it possible to observe whole array and react on single property from element change? Not sure how am I supposed to achieve this.
Probably my approach to this case is totally wrong. However I am not sure how am I supposed to operate here in a different way.
The entity
and isSelected
variables need to be lets and not vars.
Here's the solution I came up with:
let selectedsAndAmounts = invoices
.asObservable()
.flatMapLatest {
Observable.combineLatest($0.map {
Observable.combineLatest($0.isSelected.asObservable(), Observable.just($0.amount)) { (isSelected: $0, amount: $1) }
})
}
let allSelected = selectedsAndAmounts
.map { $0.map { $0.isSelected } }
.map { $0.contains(false) == false }
let amountOfSelected = selectedsAndAmounts
.map { $0.map { $0.isSelected ? $0.amount : 0 } }
.map { $0.reduce(0, +) }
Most of the complexity in this solution (the selectedsAndAmounts
observable) comes from having to unwrap the observables inside observables. It would be better if you could break this up a bit, or remove the Variables from inside the InvoiceDataModel.
First off, note that Variable is deprecated in RxCocoa (use BehaviorRelay instead).
A brief solution would to combine the isSelected
observables into a single, amount emitting observable. I just threw this snippet together, but it should point you in the right direction.
invoices
// whenever the list changes, subscribe to the combined observable (and dispose of any previous subscriptions)
.flatMapLatest { list in
// merge all isSelected observables together
return Observable.merge(list.map { $0.isSelected })
}
// when an element is emitted, that means some `isSelected` observable has changed its value
// get the latest invoices array
.withLatestFrom(invoices)
// convert it from a InvoiceDataModel array to a summed amount of all elements
.map { $0.reduce(0) { $0 + $1.amount } }
// log all events passing through
.debug()
.subscribe()
.disposed(by: yourDisposeBag)
You can use a similar approach to subscribe to an Observable that emits if all items are selected. (Don't forget about .distinctUntilChanged()
, otherwise you're going to see a lot of emitted elements.)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.