im trying to make a list builder with bloc that adds a widget to make variants of a product, but when i press the button it wont add a new widget, it should be more clear with the images. Size is not the issue since
This is the code with the bloc builder
class MarketplaceAddServiceForm extends StatelessWidget {
const MarketplaceAddServiceForm({
Key? key,
required GlobalKey<FormState> formKey,
required this.usecase,
required this.addServiceProvider,
}) : _formKey = formKey,
super(key: key);
final GlobalKey<FormState> _formKey;
final AddServiceUsecase usecase;
final RegisterServiceBloc addServiceProvider;
@override
Widget build(BuildContext context) {
return BlocConsumer<RegisterServiceBloc, RegisterServiceState>(
listenWhen: (previous, current) {
return current is SuccessRegisterServiceState ||
current is ErrorRegisterServiceState;
},
listener: (context, state) {
validateServiceForm(state, context);
},
builder: (context, state) {
return Container(
padding: EdgeInsets.all(ScreenUtils.percentHeight(context, 2)),
margin: EdgeInsets.only(left: ScreenUtils.percentHeight(context, 2)),
width: ScreenUtils.percentWidth(context, 80),
child: SingleChildScrollView(
child: Column(
children: [
Form(
key: _formKey,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
const VerticalSpace(),
const VerticalSpace(),
Row(children: [
MarketplaceAddServiceNameTextfield(
controller: usecase.name),
MarketplaceChooseTypeService()
]),
BlocBuilder<AddVariantBloc, AddVariantState>(
buildWhen: (previous, current) => current is VariantAddedState,
builder: (context, state) {
if(state is VariantAddedState){
return Column(
children: (List.generate(
state.variants.length,
(index) =>
Container(child: state.variants[index]),
)),
);
} return VariantTextfield(usecase: usecase);
},
),
const VerticalSpace(),
const VerticalSpace(),
MarketplaceAddProductVariantButton(),
BlocBuilder<AddVariantBloc, AddVariantState>(
buildWhen: (previous, current) => current is VariantAddedState,
builder: (context, state) {
if(state is VariantAddedState){
return Column(
children: (List.generate(
state.variants.length,
(index) =>
Container(child: state.variants[index]),
)),
);
} return VariantTextfield(usecase: usecase);
},
),
The button that should add a new one.
InkWell(
onTap: () {
var usecase = AddServiceUsecase();
variants.add(VariantTextfield(usecase: usecase));
BlocProvider.of<AddVariantBloc>(context).add(VariantAddedEvent(variants: variants ));
},
blocs
class AddVariantBloc extends Bloc<AddVariantEvent, AddVariantState> {
AddVariantBloc() : super(AddVariantInitial()) {
on<VariantAddedEvent>((event, emit) {
emit(VariantAddedState(variants: event.variants));
});
}
}
abstract class AddVariantEvent extends Equatable {
const AddVariantEvent();
@override
List<Object> get props => [];
}
class VariantAddedEvent extends AddVariantEvent {
List variants;
VariantAddedEvent({
required this.variants,
});
@override
List<Object> get props => [variants];
}
abstract class AddVariantState extends Equatable {
const AddVariantState();
@override
List<Object> get props => [];
}
class AddVariantInitial extends AddVariantState {}
class VariantAddedState extends AddVariantState {
List variants;
VariantAddedState({
required this.variants,
});
@override
List<Object> get props => [variants];
}
This is how it should work:
Thank you in advance.
CodePudding user response:
Equatable properties should always be copied rather than modified. If an Equatable class contains a List or Map as properties, be sure to use List.from or Map.from respectively to ensure that equality is evaluated based on the values of the properties rather than the reference.
Equatable will see the VariantAddedState
as equal each time thus the bloc will not rebuild the state, either use List.from
as mentioned in their docs
i.e emit(VariantAddedState(variants: List.from(event.variants)));
or you can emit another temp State before emitting VariantAddedState