Reputation: 1885
Im trying to connect my viewmodel to my screen using streams for the first time but im struggling to grasp the concept completely.
My Screen:
class LoginAndSignupScreen extends StatefulWidget {
LoginAndSignupScreen({@required this.viewModel});
final LoginAndSignupScreenViewModelType viewModel;
@override
State<StatefulWidget> createState() => new _LoginAndSignupScreenState();
}
class _LoginAndSignupScreenState extends State<LoginAndSignupScreen> {
Widget showErrorMessage() {
return StreamBuilder<String>(
initialData: "",
stream: widget.viewModel.errorText,
builder: (context, snapshot) {
return new Text(
snapshot.data,
style: TextStyle(
fontSize: 13.0,
color: Colors.red,
height: 1.0,
fontWeight: FontWeight.w300
),
);
}
);
}
My view model:
abstract class LoginAndSignupScreenViewModelType {
Stream<String> get errorText;
void signIn(String email, String password);
void signUp(String email, String password, String firstName, String lastName);
}
class LoginAndSignupScreenViewModel implements LoginAndSignupScreenViewModelType {
LoginAndSignupScreenViewModel({@required this.authenticationService,
@required this.cloudStoreService});
final AuthenticationServiceType authenticationService;
final CloudStoreServiceType cloudStoreService;
final errorController = StreamController<String>.broadcast();
@override
Stream<String> get errorText => errorController.stream;
@override
void signIn(String email, String password) async {
try {
String userId = await authenticationService.signIn(email, password);
User user = await cloudStoreService.fetchUserWithId(userId)
.whenComplete(loginCallback);
print('Signed in: ${user.firstName} ${user.lastName}');
} catch (error) {
errorController.add(error);
}
}
@override
void signUp(String email, String password, String firstName, String lastName) async {
try {
String userId = await authenticationService.signUp(email, password);
User user = new User(userId, firstName, lastName);
await cloudStoreService.createUser(user)
.then(showHomeScreenIfValidUser);
print('Signed up user: ${user.id}');
} catch (error) {
errorController.add(error);
}
}
}
When I do this and run I get an error saying that snapshot.data = null
which I understand. My issue is I want there to be no widget if there is no error string.
Can anyone help?
Upvotes: 0
Views: 857
Reputation: 3716
To answer your question, different widgets can be returned depending on the value of snapshot.data
:
stream: widget.viewModel.errorText,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Text(
snapshot.data,
style: TextStyle(
fontSize: 13.0,
color: Colors.red,
height: 1.0,
fontWeight: FontWeight.w300
),
);
}
// returns an invisible widget
return SizedBox.shrink();
}
That aside, did you know that you can have a Stream
that yields both data and errors? I wonder why you are using callbacks instead of just one stream for everything, where snapshot.data
has data, and snapshot.error
has errors.
Upvotes: 1