bloc icon indicating copy to clipboard operation
bloc copied to clipboard

Text form field not updated with on-changed method Also state is rebuild multiple time

Open cdp6411 opened this issue 2 years ago • 7 comments

I want to update and clear text field after add data and when i open keyboard back arrow is blinking so much time.

https://user-images.githubusercontent.com/51112143/175351905-8ae94b69-fd0b-4bb3-a59b-fe039f717ce6.mp4

cdp6411 avatar Jun 23 '22 16:06 cdp6411

@cdp6411 can you please show your widget tree?

dhruvanbhalara avatar Jun 25 '22 16:06 dhruvanbhalara

@dhruvanbhalara This is my screen widget tree Screenshot 2022-06-27 at 7 45 46 PM This is cubit file code. Screenshot 2022-06-27 at 7 45 56 PM

cdp6411 avatar Jun 27 '22 14:06 cdp6411

@dhruvanbhalara Any idea about this or give me another method to achieve this ?

cdp6411 avatar Jul 07 '22 10:07 cdp6411

@cdp6411 unfortunately I'm not able to reproduce this issue.

dhruvanbhalara avatar Jul 09 '22 06:07 dhruvanbhalara

Hello @dhruvanbhalara Can you please try my code any reproduce the issue.

Hive Model

@HiveType(typeId: 12)
class RemarkModel {
  @HiveField(0)
  String? requirement;

  RemarkModel({this.requirement});
}

declare in main file 
Hive
..registerAdapter<RemarkModel>(RemarkModelAdapter());

 await Hive.initFlutter();
 await hiveCRUDOperations.openBox();

static late Box<RemarkModel> remarkModel;
remarkModel = await Hive.openBox<RemarkModel>("remark_model");

//add data in into list

  Future<bool> remarkModelAdd({required RemarkModel remarkModels}) async {
    await remarkModel.add(remarkModels);
    return true;
  }

// get list from database
 
List<RemarkModel> getRemarkModelData() {
    return remarkModel.values.toList();
  }


//delete from database

Future<bool> deleterRemarkModel({required int index}) async {
    await remarkModel.deleteAt(index);
    return true;
  }

//update data from index

Future<bool> updateRemarkModel(
      {required int index, required RemarkModel remarkModels}) async {
    await remarkModel.putAt(index, remarkModels);
    return true;
  }

// state file

class RemarksState extends Equatable {
  final String? remark;
  final String? remarkExtra;
  final bool? remarkFocus;
  final bool isRemarkValid;
  final String? remarkErrorMessage;
  final bool isLoading;
  final int? updateIndex;
  final bool? isEdit;
  final List<RemarkModel>? remarkList;

  RemarksState(
      {this.remark = '',
      this.remarkExtra = '',
        this.remarkFocus,
        this.isRemarkValid = true,
        this.remarkErrorMessage,
        this.isLoading = false,
        this.updateIndex,
        this.isEdit = false,
        this.remarkList});

  RemarksState copyWith(
      {final String? remark,
      final String? remarkExtra,
        final bool? remarkFocus,
        final bool? isRemarkValid,
        final String? remarkErrorMessage,
        final bool? isLoading,
        final int? updateIndex,
        final bool? isEdit,
        final List<RemarkModel>? remarkList}) {
    return RemarksState(
        remark: remark ?? this.remark,
        remarkExtra: remarkExtra ?? this.remarkExtra,
        remarkFocus: remarkFocus ?? this.remarkFocus,
        isRemarkValid: isRemarkValid ?? this.isRemarkValid,
        remarkErrorMessage:
        remarkErrorMessage ?? this.remarkErrorMessage,
        isLoading: isLoading ?? this.isLoading,
        updateIndex: updateIndex ?? this.updateIndex,
        isEdit: isEdit ?? this.isEdit,
        remarkList: remarkList ?? this.remarkList);
  }

  @override
  List<Object?> get props => [
    remark,
    remarkExtra,
    remarkFocus,
    isRemarkValid,
    remarkErrorMessage,
    isLoading,
    updateIndex,
    isEdit,
    remarkList
  ];
}

// cubit file

class RemarksCubit extends Cubit<RemarksState> {
  RemarksCubit() : super(RemarksState());

  getPreData() {
    emit(state.copyWith(
        remarkList: hiveCRUDOperations.getRemarkModelData()));
  }

  void changeFocus(String? textField) {
    if (textField == TextFieldConstants.only_remark) {
      emit(state.copyWith(remarkFocus: true));
    }  else {
      emit(state.copyWith(remarkFocus: false));
    }
  }

  void addRemark(String value) {
    emit(state.copyWith(
        remark: value,
        isRemarkValid: value.isNotEmpty ? true : false));
  }

  void clear(){
    emit(state.copyWith(remark: ""));
  }

  void remarkEdit(String remark, int index) {
    emit(state.copyWith(
        remark: remark,
        remarkExtra: remark + "Extra",
        isEdit: true,
        updateIndex: index));
  }

  bool chekValidations() {
    bool isValid = true;
    emit(state.copyWith(remarkFocus: false));
    if (state.remark == '') {
      emit(state.copyWith(isRemarkValid: false));
      isValid = false;
    }
    return isValid;
  }

  Future<bool> saveDescriptionData(
      {required BuildContext context,
        required String remark}) async {
    emit(state.copyWith(isLoading: true));

    bool isSuccess = await hiveCRUDOperations.remarkModelAdd(
        remarkModels: RemarkModel(requirement: remark));

    if (isSuccess) {
      emit(state.copyWith(isLoading: false));
      emit(state.copyWith(
          remarkList: hiveCRUDOperations.getRemarkModelData()));
    } else {
      emit(state.copyWith(isLoading: false));
    }
    emit(state.copyWith(isLoading: false));
    return isSuccess;
  }

  Future<void> deleteRemark(
      {required BuildContext context, required int index}) async {
    emit(state.copyWith(isLoading: true));
    bool isSuccess =
    await hiveCRUDOperations.deleterRemarkModel(index: index);

    if (isSuccess) {
      emit(state.copyWith(isLoading: false));
      emit(state.copyWith(
          remarkList: hiveCRUDOperations.getRemarkModelData()));
    } else {
      emit(state.copyWith(isLoading: false));
    }
    emit(state.copyWith(isLoading: false));
  }

  Future<void> updateRemark(
      {required BuildContext context,
        required int index,
        required String remark}) async {
    emit(state.copyWith(isLoading: true));

    bool isSuccess = await hiveCRUDOperations.updateRemarkModel(
        index: index,
        remarkModels: RemarkModel(
            requirement: remark));
    if (isSuccess) {
      emit(state.copyWith(isLoading: false, isEdit: false));
      emit(state.copyWith(
          remarkList: hiveCRUDOperations.getRemarkModelData()));
    } else {
      emit(state.copyWith(isLoading: false));
    }
    emit(state.copyWith(isLoading: false));
  }
}


// screen design and bloc code

class RemarkScreen extends StatelessWidget {
  RemarkScreen({Key? key}) : super(key: key);

  static const route = '/remark_screen';
  final SlidableController slideController = SlidableController();

  @override
  Widget build(BuildContext context) {
    return BlocProvider(
      create: (context) => RemarksCubit()..getPreData(),
      child: Scaffold(
        appBar: AppBar(
          title: Text("Remarks", style: TextStyle(fontFamily: "Montserrat")),
        ),
        body: SafeArea(
          child: SingleChildScrollView(
            padding: EdgeInsets.all(10.sp),
            child: Column(
              children: [
                BlocBuilder<RemarksCubit, RemarksState>(
                  builder: (ctx, state) {
                    return TextFormField(
                      key: Key(state.remarkExtra!),
                      onChanged: (value) {
                        ctx.read<RemarksCubit>().addRemark(value.trimRight());
                      },
                      onTap: () {
                        ctx
                            .read<RemarksCubit>()
                            .changeFocus(TextFieldConstants.only_remark);
                      },
                      initialValue: state.remark,
                      decoration: InputDecoration(
                          filled: true,
                          fillColor: state.remarkFocus ?? false
                              ? AppColors.white
                              : AppColors.textFieldBG,
                          hintText: "Remarks"),
                    );
                  },
                ),
                SizedBox(height: 6.h),
                BlocBuilder<RemarksCubit, RemarksState>(
                  builder: (ctx, state) {
                    print(state.remark);
                    return SizedBox(
                      height: 46.h,
                      width: 200.w,
                      child: ElevatedButton(
                          style: ElevatedButton.styleFrom(
                            elevation: 6.sp,
                          ),
                          onPressed: () async {
                            FocusManager.instance.primaryFocus?.unfocus();
                            // if (state.isLoading) return;
                            bool isValidForm =
                                ctx.read<RemarksCubit>().chekValidations();
                            if (isValidForm) {
                              if (state.isEdit!) {
                                await ctx.read<RemarksCubit>().updateRemark(
                                      context: context,
                                      remark: state.remark!,
                                      index: state.updateIndex!,
                                    );
                              } else {
                                await ctx
                                    .read<RemarksCubit>()
                                    .saveDescriptionData(
                                        context: context,
                                        remark: state.remark!);
                              }
                              ctx.read<RemarksCubit>().clear();
                            }
                          },
                          child: state.isLoading
                              ? const CircularProgressIndicator(
                                  valueColor: AlwaysStoppedAnimation<Color>(
                                      AppColors.white),
                                )
                              : Text(state.isEdit! ? "Update" : "Add")),
                    );
                  },
                ),
                SizedBox(height: 20.h),
                BlocBuilder<RemarksCubit, RemarksState>(builder: (ctx, state) {
                  return state.remarkList!.isNotEmpty
                      ? ListView.builder(
                          shrinkWrap: true,
                          physics: NeverScrollableScrollPhysics(),
                          itemCount: state.remarkList?.length,
                          itemBuilder: (context, index) {
                            return Container(
                              margin: EdgeInsets.symmetric(vertical: 10.h),
                              child: Material(
                                borderRadius:
                                    BorderRadius.all(Radius.circular(10.sp)),
                                elevation: 10.sp,
                                child: Slidable(
                                  controller: slideController,
                                  actionExtentRatio: 0.20,
                                  closeOnScroll: true,
                                  secondaryActions: [
                                    IconSlideAction(
                                        color: Colors.white,
                                        foregroundColor: Colors.blue,
                                        icon: Icons.edit,
                                        onTap: () {
                                          ctx.read<RemarksCubit>().remarkEdit(
                                              state.remarkList![index]
                                                  .requirement!,
                                              index);
                                        }),
                                    IconSlideAction(
                                        color: Colors.white,
                                        foregroundColor: Colors.red,
                                        icon: Icons.delete,
                                        onTap: () async {
                                          await ctx
                                              .read<RemarksCubit>()
                                              .deleteRemark(
                                                  context: context,
                                                  index: index);
                                        }),
                                  ],
                                  actionPane: const SlidableDrawerActionPane(),
                                  child: Container(
                                    width: double.infinity,
                                    padding: EdgeInsets.all(10.sp),
                                    decoration: BoxDecoration(
                                        color: AppColors.textFieldBG,
                                        border: Border.all(
                                            color: AppColors.titleTextColor,
                                            width: 1.w),
                                        borderRadius: BorderRadius.all(
                                            Radius.circular(10.sp))),
                                    child: Column(
                                      crossAxisAlignment:
                                          CrossAxisAlignment.start,
                                      mainAxisSize: MainAxisSize.min,
                                      children: [
                                        Text(
                                            "Description :- ${state.remarkList![index].requirement!}",
                                            style: TextStyle(
                                                color: AppColors.titleTextColor,
                                                fontFamily: "Montserrat",
                                                fontSize: 18.sp,
                                                fontWeight: FontWeight.bold)),
                                      ],
                                    ),
                                  ),
                                ),
                              ),
                            );
                          })
                      : Center(
                          child: Text("No Records Found.",
                              style: TextStyle(
                                  fontFamily: "Montserrat",
                                  fontSize: 20.sp,
                                  fontWeight: FontWeight.bold)));
                })
              ],
            ),
          ),
        ),
      ),
    );
  }
}

Try it.

cdp6411 avatar Jul 09 '22 14:07 cdp6411

@cdp6411 it would be better if you provide the code in a zip file.

dhruvanbhalara avatar Jul 10 '22 13:07 dhruvanbhalara

It's because TextFields/TextFormFields have their own state managers which is the TextEditingController, so when your Bloc state changes and needs to update the text, you need something like this

final TextEditingController yourTextEditingController;
BlocListener<YourBloc, YourState>(
   listenWhen: (YourState previous, YourState current) {
      return previous.text != current.text && yourTextEditingController.text != current.text;
   },
   listener: (BuildContext context, YourState state) {
      yourTextEditingController.text = state.text;
   },
)

iandis avatar Aug 16 '22 15:08 iandis