I am trying to learn the BLoC pattern in Flutter, but I just don't get it. I followed a tutorial on Udemy from which I generated the following code for a simple login form:
BLoC Class
import 'dart:async';
import 'package:login_bloc/src/blocs/validators.dart';
class LoginBloc extends Validators {
final _email = StreamController<String>();
final _password = StreamController<String>();
// Return Stream data
// Streams are run thru validator first
Stream<String> get getEmail => _email.stream.transform(validateEmail);
Stream<String> get getPassword => _password.stream.transform(validatePassword);
// Change data on stream
Function(String) get changeEmail => _email.sink.add;
Function(String) get changePassword => _password.sink.add;
// Named by convention. Quiets Dart warning.
dispose() {
_email.close();
_password.close();
}
}
UI Class
import 'package:flutter/material.dart';
import 'package:login_bloc/src/blocs/login_bloc.dart';
import 'package:login_bloc/src/providers/provider.dart';
class LoginScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
final loginBloc = Provider.of(context);
return Padding(
padding: const EdgeInsets.all(16.0),
child: SafeArea(
child: Column(
children: <Widget>[
emailField(loginBloc),
passwordField(loginBloc),
SizedBox(height: 10.0),
submitButton(),
],
),
),
);
}
Widget emailField(LoginBloc loginBloc) {
return StreamBuilder<Object>(
stream: loginBloc.getEmail,
builder: (context, snapshot) {
return TextField(
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
hintText: 'you@example.com',
labelText: 'Email Address',
errorText: snapshot.error,
),
onChanged: loginBloc.changeEmail,
);
});
}
Widget passwordField(LoginBloc loginBloc) {
return StreamBuilder<Object>(
stream: loginBloc.getPassword,
builder: (context, snapshot) {
return TextField(
obscureText: true,
keyboardType: TextInputType.text,
decoration: InputDecoration(
labelText: 'Password',
errorText: snapshot.error,
),
onChanged: loginBloc.changePassword,
);
});
}
Widget submitButton() {
return RaisedButton(
child: Text(
'Login',
style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold),
),
color: Colors.blue,
onPressed: () => {},
);
}
}
The validators are super simple: basically the email needs an '@' sign and the password has to be more than 4 chars. It makes sense as I follow along, but as soon as I try to implement on my own, it goes fuzzy. So, as part of my learning, I wanted to try and convert this simple login form to utilize the BLoC and Flutter_BLoC libraries, thinking it would abstract away some of the complexity and be easier to understand.
After substantial work, I still can't figure out how to specify what state I'm trying to hold, and what events I'm trying to pass. I've run out of tutorials to view on YouTube and they nearly all use the counter app as an example with a single INT variable type. It's also complicated by the fact that the library just had a HUGE overhaul, and nearly all the tutorials are now outdated.
Are there any examples available of how to do this using the v6 library? In particular, I am interested in how to activate the submit button only when both fields have been validated.
You can use rxdart package which can be found here. Rxdart adds additional capabilities to Dart Streams and StreamControllers. One of those is combineLatest2()
which basically combines the value of the 2 streams and be emitted as a single stream value.
You can read more about combineLatest2()
method from this link.
Example:
Stream<bool> get isValid => Rx.combineLatest2(getEmail, getPassword, (a,b) => true);