Part 2 - BLoC class

Properties

To handle all the fields, it is declared a StreamedList of StreamedValue<String> for each one of the two types of fields, name, and age. This is necessary to make it possible adding new fields associated with a stream and handle their validation (see the checkForm method).

final nameFields = StreamedList<StreamedValue<String>>(initialData: []); final ageFields = StreamedList<StreamedValue<String>>(initialData: []);

The property isFormValid (a StramedValue<bool> ) is used to stream the current state of the form. This will be used to drive a StreamBuilder widget in the DynamicFieldsWidget (explained in the next step) to enable or disable the submit button.

final isFormValid = StreamedValue<bool>();

Constructor

In the constructor, both the StreamedList are initialized with three StreamedValue<String> each one, so that the app starts with three pairs of name/age fields filled with some values.

Then, to the onChange method of every StreamedValue is assigned the checkForm method in order to trigger the checking of all the fields every time a single field changes.

DynamicFieldsBloc() {

print(‘ — — — -DynamicFields BLOC — — — — ‘); // Adding the initial three pairs of fields to the screen

nameFields.addAll([

StreamedValue<String>(initialData: ‘Name AA’),

StreamedValue<String>(initialData: ‘Name BB’),

StreamedValue<String>(initialData: ‘Name CC’)

]); ageFields.addAll([

StreamedValue<String>(initialData: ‘11’),

StreamedValue<String>(initialData: ‘22’),

StreamedValue<String>(initialData: ‘33’)

]); // Set the method to call every time the stream emits a new event

for (var item in nameFields.value) {

item.onChange(checkForm);

} for (var item in ageFields.value) {

item.onChange(checkForm);

}

}

checkForm

The checkForm method is called every time a field changes and detects if there are fields not valid. In this example, for the name fields, it is just checked if the string is not empty, otherwise, an error is sent to the stream. Instead, for the age fields is checked if the value is not null and it is between 1 and 130.

The boolean variables isValidFieldsTypeName and isValidFieldsTypeAge are set to true by default: the corresponding boolean is set to false when a field of that type (name or age) is not valid.

In the last lines, is checked if both these boolean are true: this means that all fields are valid. In this case, isFormValid (a StreamedType<bool> ) is set to true, a true event is sent to stream triggering the StreamBuilder to rebuild the widget with the new value, enabling the submit button. Otherwise, if at least one field is not valid, the condition of the if is not met and isFormValid is set to false (the submit button will be disabled).

newFields

This method is used to add a new pair of name/age fields to the screen. In the first two lines, a new StreamedValue<String> is added to the nameFields and ageFields StreamedList and to its onChange method is assigned the checkForm method like seen in the constructor. Finally, the checkForm method is called to detect the new fields that, having an empty value, will cause the disabling of the submit button.