9

There is a StreamBuilder (using RxDart) which displays some date. After click on InkWell widget I need to calculate a new date on basis of old one. The code below simply explains the algo but when I run it there is nothing happens and execution stops after underlined row, i.e. I never see the value of lastCalcDate.

GUI:

child: StreamBuilder(
  stream: bloc.getDate,
  builder: (context,snapshot) {
    return InkWell(
      onTap: () => tapHandler
    );
}),

void tapHandler() async {
  var lastCalcDate = await bloc.getDate.single;
  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  print(lastCalcDate);
  var newCalcDate = lastCalcDate.add(Duration(days:1));
  bloc.setDate(newCalcDate)
}

BLoC:

class Bloc {
  // BehaviourSubject is usedto be sure that last sent date will be accessible in `tapHandler`.
  final _dateSubject = BehaviourSubject<DateTime>(); 
  Observable<DateTime> get getDate => _dateSubject.stream;
  Function(DateTime) get setDate => _dateSubject.add;
}

To implement what I need I created some workaround but I don't like it because I fill that I can do the same thing using observables.

BLoC (workaround):

class Bloc {
  final _dateSubject = BehaviourSubject<DateTime>(); 
  Observable<DateTime> get getDate => _dateSubject.stream;
  DateTime _date;
  void setDateWorkaround(DateTime date) {
    _date = date;
    _dateSubject.add(date);
  }
}

Could you someone to give me advise. What I did wrong?

creativecreatorormaybenot
  • 114,516
  • 58
  • 291
  • 402
BambinoUA
  • 6,126
  • 5
  • 35
  • 51

2 Answers2

10

single will not work because it is going to return the next item in the stream, however, that has to be added first. This means that single will just wait for the next item and in your case it will not happen.

Since you are using rxdart and BehaviorSubject already, you can easily access the current element like this:

class Bloc {
  final _dateSubject = BehaviourSubject<DateTime>(); 
  Observable<DateTime> get getDate => _dateSubject.stream;
  Function(DateTime) get setDate => _dateSubject.add;

  DateTime get currentDate => _dateSubject.value;
}

In this case, I am making use of BehaviorSubject.value, which is actually the whole point of that class.

Now, you can just use currentDate in your tap handler:

void tapHandler() async {
  var lastCalcDate = bloc.currentDate;
  print(lastCalcDate);
  var newCalcDate = lastCalcDate.add(Duration(days:1));
  bloc.setDate(newCalcDate)
}
creativecreatorormaybenot
  • 114,516
  • 58
  • 291
  • 402
  • 9
    hi, how can I get it without using rx? – ch271828n Jan 24 '21 at 04:16
  • 3
    If someone runs into the same issue: There seemed to be a breaking change in the rxdart package where you can not use .value directly on a BehaviorSubject anymore. You would have to use "_dateSubject.valueWrapper.value". The link in this answer to the BeahviorSubject.value documentation is invalid now. – kk_ Apr 03 '21 at 09:55
1

Use StreamProvider from provider

Listen to a Stream and expose the latest value emitted.

Yanni
  • 580
  • 2
  • 6
  • 21