Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to change state of individual list items using bloc flutter?

How to change the widgets in a list item in flutter using bloc pacakage. Should i use BlockBuilder or listener on the whole ListView.builder or only the individual items. It would be nice if u share an example or tutorial. eg If i have a checkbox i need to change its state on clicking it. These are my Bloc classes Bloc

const String SERVER_FAILURE_MESSAGE = 'Server Failure';
const String CACHE_FAILURE_MESSAGE = 'Cache Failure';
class MarkAttendanceBloc extends Bloc<MarkAttendanceEvent, MarkAttendanceState> {

  final MarkStudentPresent markStudentPresent;
  final MarkStudentAbsent markStudentAbsent;

  MarkAttendanceBloc({@required this.markStudentPresent,@required this.markStudentAbsent});

  @override
  MarkAttendanceState get initialState => MarkedInitial();

  @override
  Stream<MarkAttendanceState> mapEventToState(MarkAttendanceEvent event) async* {
    yield MarkedLoading();
    if(event is MarkAbsentEvent){
      final remotelyReceived = await markStudentAbsent(MarkStudentParams(classId: event.classId, courseId: event.courseId,studentId: event.studentId));
      yield* _eitherLoadedOrErrorState(remotelyReceived);
    }
    else if(event is MarkPresentEvent){
      final remotelyReceived = await markStudentPresent(MarkStudentParams(classId: event.classId, courseId: event.courseId,studentId: event.studentId));
      yield* _eitherLoadedOrErrorState(remotelyReceived);
    }
  }
  Stream<MarkAttendanceState> _eitherLoadedOrErrorState(
    Either<StudentDetailsFacultyFailure,int> failureOrClasses,
    ) async* {
    yield failureOrClasses.fold(
        (failure) => MarkedError(_mapFailureToMessage(failure)),
        (studentId) => Marked(studentId),
    );
  }
  String _mapFailureToMessage(StudentDetailsFacultyFailure failure) {
    switch (failure.runtimeType) {
      case ServerError:
        return SERVER_FAILURE_MESSAGE;
      default:
        return 'No internet';
    }
  }

}

State

abstract class MarkAttendanceState extends Equatable{
  const MarkAttendanceState();
}

class MarkedInitial extends MarkAttendanceState{
  const MarkedInitial();
  @override
  List<Object> get props => [];

}

class MarkedLoading extends MarkAttendanceState{
  const MarkedLoading();
  @override
  List<Object> get props => [];

}

class Marked extends MarkAttendanceState{
  final int studentId;

  Marked(this.studentId);

  @override
  List<Object> get props => [studentId];

}

class MarkedError extends MarkAttendanceState{
  final String errorMessage;
  MarkedError(this.errorMessage);
  @override
  List<Object> get props => [errorMessage];
}

Event

import 'package:equatable/equatable.dart';

abstract class MarkAttendanceEvent extends Equatable {
  const MarkAttendanceEvent();
}
class MarkPresentEvent extends MarkAttendanceEvent {
  final int studentId;
  final int courseId;
  final int classId;

  MarkPresentEvent(this.studentId, this.courseId, this.classId);

  @override
  List<Object> get props =>[studentId,courseId,classId];

}

class MarkAbsentEvent extends MarkAttendanceEvent {
  final int studentId;
  final int courseId;
  final int classId;

  MarkAbsentEvent(this.studentId, this.courseId, this.classId);

  @override
  List<Object> get props =>[studentId,courseId,classId];

}
like image 989
Harshvardhan R Avatar asked Jun 26 '20 13:06

Harshvardhan R


People also ask

Which is better BLoC or provider Flutter?

So here, we can compare the StreamBuilder in Bloc with Consumer in Provider. The difference is that StreamBuilder listens to the stream and fetches the model on every change to rebuild the widget. But Consumer listens as soon as notifyListeners() executes inside the provider class.


1 Answers

Maybe by now you have found a solution but this is how i managed to achieve the same functionality using flutter cubits. This code is hand written and not tested but it should guide you to achieve your goal

1 Declare the class objects

    class ClassItem{
      int? price;
      bool isChecked;
    
      ClassItem({
        this.price,
        this.isChecked=false,
      });
}
    class ClassOverall{
      List<ClassItem> items;
      double? total;
      ClassOverall(this.items,this.total);
    }
  1. Declare the cubit class

      class OverallCubit extends Cubit<ClassOverall> {
      OverallCubit(ClassOverallinitialState) : super(initialState);
    
      void checkUncheckCart(int index) {
      if (!state.items
          .elementAt(index).isChecked) {
        state.items
                .elementAt(index).isChecked =
            !state.items
                .elementAt(index).isChecked;
        var t_total = double.tryParse(state.items
                .elementAt(index).price!)! * 1;
        emit(OverallCubit (state.items,state.total));
      } else {
        state.items.elementAt(index).isChecked =
            !state.items
                .elementAt(index).isChecked;
        emit(OverallCubit (state.items,state.total));
      }
      calculateTotal();
    }
    void calculateTotal() {
      var tot = 0.0;
        for (var tick in state.items) {
          if (tick.isChecked) {
            tot = (tick.t_total! + tot);
    
      }
    
      }
    emit(OverallCubit (state.items,tot));
     }
     }
    
  2. Declare the top class widget to hold the state

    class TopState extends StatelessWidget {
          @override
          Widget build(BuildContext context) {
            return BlocProvider(
              create: (_) => OverallCubit(ClassOverall(items,0)),//fetch items from your source 
              child: Home(),
            );
          }
        }
    
  3. Declare the stateful widget and add a bloc builder

     class Home extends StatefulWidget {
            @override
       _HomePageState createState() => _HomePageState();
     }
    
     class _HomePageState extends State<Home> {
       @override
       Widget build(BuildContext context) {
         return  BlocBuilder<OverallCubit, ClassOverall>(
                                   builder: (ctx, state) {
     return Column(children:[ 
     ListView.builder(
     padding: EdgeInsets.all(0.0),
                                           shrinkWrap: true,
                                           itemCount: state.items.length,
                                           itemBuilder: (context, index) {
                                             return ListTile(
     onTap: () {
                 ctx
                     .read<OverallCubit>()
                     .checkUncheckCart(index);
               },
     tileColor: state.elementAt(index).isChecked ? Colors.red : Colors.white
     title: Text(state.items.elementAt(index).price!),
     );
     }),
     Text(state.total.toString),
     ]);
                                      });
     }
    
     }
    
like image 79
D. Ndungu Avatar answered Sep 18 '22 17:09

D. Ndungu