Kush Vatsa
Kush Vatsa

Reputation: 375

How to show functions callback and errors on UI with bloc pattern in Flutter?

bloc.dart

class Bloc{
Bloc(){
additionalController.stream.listen(onAdd);
}

void dispose() async {
additionalController.close();
_itemAdd.close();
}

final additionalController = StreamController<Data>();
Sink<Data> get addItem => additionalController.sink;

Stream<String> get addGet => _itemAdd.stream;
final _itemAdd = BehaviorSubject<String>();

void onAdd(Data data) {
_addWork(data);
}

Future<Null> _addWork(Data data) async {

//work

}).whenComplete(() {

_itemAdd.add("complete work");

}).catchError((e) {
_itemAdd.addError("Error in Adding Data");
  });
 }
}

As bloc should only be used and shared to handle the business logic, but the error handling part has nothing to do with the business logic.

How to show callbacks and error of bloc on UI. I don't think StreamBuilder is the only solution.

If we use StreamBuilder, In that way, We repetitively send callback to bloc every time rebuilding happens and this make no sense.

Is there a right way to do this?

Thank you in advance!!

Upvotes: 1

Views: 4045

Answers (2)

Ernest
Ernest

Reputation: 79

According to the Dart docs this can be done in Dart 2.1 with mixin:

Version note: Support for the mixin keyword was introduced in Dart 2.1. Code in earlier releases usually used abstract class instead. For more information on 2.1 mixin changes, see the Dart SDK changelog and 2.1 mixin specification.

Example:

 mixin Music {
  void play();
}

class Musician {
  Music _delegate;

  Musician(Music delegate){
    _delegate = delegate;
  }

  play(){
    _delegate.play();
  }
}

class MyMusicWidget extends StatelessWidget with Music{

  @override
  Widget build(BuildContext context) {
    return Container(
      child: Text("Music")
    );
  }

  @override
  void play() {
    // TODO: implement play
    // Your code here!
  }
}

Upvotes: 1

What has worked for me so far, is using an interface that represents a callback.

abstract class AddItemDelegate {
  void onSuccess();
  void onError(String message);
}

Then using it in the bloc as follows:

class Bloc {
  AddItemDelegate _delegate;
  // ...
  Function addItem(Data item, AddItemDelegate delegate) => () {
    _delegate = delegate;
    additionalController.sink.add(item);
  }
  // ...
  Future<Null> _addWork(Data data) async {
    try {
      final work = await //work...
      _itemAdd.add("complete work");
      _delegate?.onSuccess();
    }
    catch(e) {
      final error = "Error in Adding Data";
      _itemAdd.addError(error);
      _delegate?.onError(error);
    }
  }
}

Then on your StatefulWidget (orStatelessWidget) you can do the following:

class MyWidget extends StatelessWidget implements AddItemDelegate {
  @override
  void onSuccess() {
    // e.g.: Show a dialog or navigate to other screen
  }

  @override
  void onError(String message) {
    // e.g.: Show an error dialog
  }

  @override
  Widget build(BuildContext context) {
    final bloc = // ...
    final data = // ...
    return MaterialButton(
        child: Text("Add Item"), 
        onPressed: bloc.addItem(data, this));
  }
}

This way one can use callbacks while using BLoC pattern.

Upvotes: 12

Related Questions