bloc
bloc copied to clipboard
Text form field not updated with on-changed method Also state is rebuild multiple time
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 can you please show your widget tree?
@dhruvanbhalara
This is my screen widget tree
This is cubit file code.
@dhruvanbhalara Any idea about this or give me another method to achieve this ?
@cdp6411 unfortunately I'm not able to reproduce this issue.
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 it would be better if you provide the code in a zip file.
It's because TextField
s/TextFormField
s 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;
},
)