Null Safety Issue in flutter - flutter

if (_formKey.currentState.validate()) {
setState(() {
buttonChanged = false;
});
}
according to my logic, the above statement would let me sign in with a login and password validation, but i keep getting an error
The method 'validate' can't be unconditionally invoked because the receiver can be 'null'.
Try making the call conditional (using '?.') or adding a null check to the target ('!').
when i do if (_formKey.currentState!.validate()) error goes away but my validation does not work, login happens even when it shouldnt.
Kindly help me with this issue, i am a beginner, learning flutter app developement via youtube.
this is my whole code
import 'package:flutter/material.dart';
import 'routes.dart';
class LoginPage extends StatefulWidget {
const LoginPage({Key? key}) : super(key: key);
#override
State<LoginPage> createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
bool buttonChanged = false;
String name = "";
final _formKey = GlobalKey<FormState>();
moveToHome(BuildContext context) async {
if (_formKey.currentState.validate()) {
setState(() {
buttonChanged = false;
});
}
await Future.delayed(const Duration(seconds: 1));
await Navigator.pushNamed(context, route.home);
setState(() {
buttonChanged = false;
});
}
#override
Widget build(BuildContext context) {
return Material(
color: Colors.grey[500],
child: Form(
key: _formKey,
child: Column(
children: [
const CircleAvatar(backgroundImage: AssetImage('images/login.jpg')),
const SizedBox(height: 15.0),
Text('Welcome $name',
style: const TextStyle(
fontSize: 24.0, fontWeight: FontWeight.bold)),
const SizedBox(height: 15.0),
Padding(
padding:
const EdgeInsets.symmetric(horizontal: 15, vertical: 32),
child: Column(
children: [
TextFormField(
decoration: const InputDecoration(
hintText: 'Enter the username',
labelText: 'UserName:'),
onChanged: (value) {
name = value;
setState(() {});
},
validator: (value) {
if (value != null && value.isEmpty) {
return 'Please enter the username';
}
return null;
}),
TextFormField(
obscureText: true,
decoration: const InputDecoration(
hintText: 'Enter the password',
labelText: 'Password:'),
validator: (value) {
if (value != null && value.isEmpty) {
return 'Please enter the password';
} else if (value != null && value.length < 6) {
return 'Password must be atleast 6 characters';
} else {
return null;
}
}),
const SizedBox(height: 15.0),
Material(
borderRadius:
BorderRadius.circular(buttonChanged ? 50.0 : 10.0),
color: Colors.blue,
child: InkWell(
splashColor: Colors.red,
onTap: () => moveToHome(context),
child: AnimatedContainer(
duration: const Duration(seconds: 1),
width: buttonChanged ? 50 : 130,
height: 50,
alignment: Alignment.center,
child: buttonChanged
? const Icon(Icons.done)
: const Text(
'Login',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 16),
),
),
))
],
))
],
),
),
);
}
}

Your validation logic must be:
If the user’s input isn’t valid, the validator function returns a String containing an error message. If there are no errors, the validator must return null.
But you're using incorrect code in your validator property. The following code:
validator: (value) {
if (value != null && value.isEmpty) {
return 'Please enter the username';
}
return null;
}),
will always return null if you haven't insert the text to TextFormField. So,
_formKey.currentState!.validate() will always return true if both of your TextFormFields are without text.
To solve the problem, change the code like the following:
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter the username';
}
return null;
}),

Related

I am new to programming can someone help me what's the problem here, I was doing a login page and this happens

If password and username is same, I want to print 'username and password is same' statement in the terminal .But it is only printing the second statement 'username and password does not match even if username and password is same or not . I don't understand why this happened somebody help, I am new here' ( NB : problem is inside the function named checkLogin)
class ScreenLogin extends StatefulWidget {
ScreenLogin({Key? key}) : super(key: key);
#override
State<ScreenLogin> createState() => _ScreenLoginState();
}
class _ScreenLoginState extends State<ScreenLogin> {
final _usernameController = TextEditingController();
final _passwordController = TextEditingController();
bool _isDataMatched = false;
final _formkey = GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Padding(
padding: const EdgeInsets.all(15.0),
child: Form(
key: _formkey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
TextFormField(
controller: _usernameController,
decoration: const InputDecoration(
border: OutlineInputBorder(), hintText: 'Username'),
validator: (value) {
if (value == null || value.isEmpty) {
return 'value is empty';
} else {
return null;
}
},
),
const SizedBox(
height: 20,
),
TextFormField(
controller: _passwordController,
obscureText: true,
decoration: const InputDecoration(
border: OutlineInputBorder(), hintText: 'Password'),
validator: (value) {
if (value == null || value.isEmpty) {
return 'value is empty';
} else {
return null;
}
}),
SizedBox(
height: 20,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Visibility(
visible: _isDataMatched,
child: Text(
'Username and password does not match',
style: TextStyle(color: Colors.red),
),
),
ElevatedButton.icon(
onPressed: () {
if (_formkey.currentState!.validate()) {
checkLogin(context);
} else {
print('Data Empty');
}
},
icon: const Icon(Icons.check),
label: const Text('Login ')),
],
)
],
),
),
),
));
}
void checkLogin(BuildContext context) {
final _username = _usernameController;
final _password = _passwordController;
if (_password == _username) {
print('Username and password is matching');
} else {
print('Username and password does not match');
}
}
}
To get text, you need to use .text on controller.
_usernameController.text;
void checkLogin(BuildContext context) {
final _username = _usernameController.text;
final _password = _passwordController.text;
if (_password == _username) {
print('Username and password is matching');
} else {
print('Username and password does not match');
}
}
In login check you should do this:
void checkLogin(BuildContext context) {
final _username = _usernameController.text;
final _password = _passwordController.text;
if (_password == _username) {
print('Username and password is matching');
} else {
print('Username and password does not match');
}
}

how to make a button disable in flutter

I'am trying to create a profile form . I want to disable or enable the button based on the validation. I tried to check the currentstate of form validated or not. it is working fine but when i type on one of the textFormField , I am getting error message on all of the textFormField .
Here is the code i'am working.
import 'dart:html';
import 'package:flutter/material.dart';
class ProfileForm extends StatefulWidget {
const ProfileForm({Key? key}) : super(key: key);
#override
State<ProfileForm> createState() => _ProfileFormState();
}
class _ProfileFormState extends State<ProfileForm> {
final _formKey = GlobalKey<FormState>();
DateTime selectedDate = DateTime.now();
final _nameController = TextEditingController();
final _emailController = TextEditingController();
final _dobController = TextEditingController();
final _currentLocationController = TextEditingController();
final _locationIndiaController = TextEditingController();
bool btndisable = false;
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
RegExp emailValidator = RegExp(
r'^(([^<>()[\]\\.,;:\s#\"]+(\.[^<>()[\]\\.,;:\s#\"]+)*)|(\".+\"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$');
return Scaffold(
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Form(
key: _formKey,
onChanged: () {
notdisbled();
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Let’s create a profile for you",
style: AppTextStyleSecondary.headline2sec,
),
const SizedBox(
height: 12,
),
Padding(
padding: const EdgeInsets.only(right: 100.0),
child: Text(
"Please enter your personal details",
),
),
const SizedBox(
height: 16,
),
Text("Your name"),
TextFormField(
autovalidateMode: AutovalidateMode.onUserInteraction,
onChanged: (val) {
},
validator: (val) {
if (val.toString().length < 2) {
return "Please enter your name";
}
return null;
},
controller: _nameController,
decoration: const InputDecoration(
isDense: true,
contentPadding:
EdgeInsets.symmetric(horizontal: 10, vertical: 12)),
),
Text(labelText: "Date of Birth"),
InkWell(
child: TextFormField(
onTap: () {
_selectDate(context);
},
validator: (val) {
if (val.toString().isEmpty) {
return "This field is required";
} else {
return null;
}
},
readOnly: true,
controller: _dobController,
),
),
Text("Email address"),
TextFormField(
controller: _emailController,
onChanged: (val) {},
autovalidateMode: AutovalidateMode.onUserInteraction,
validator: (val) {
String email = val!.trim();
if (emailValidator.hasMatch(email)) {
return null;
} else {
return "Enter valid email address";
}
},
decoration: const InputDecoration(
isDense: true,
contentPadding:
EdgeInsets.symmetric(horizontal: 10, vertical: 12)),
),
Text(labelText: "Your location where you currently live"),
TextFormField(
autovalidateMode: AutovalidateMode.onUserInteraction,
validator: (val) {
if (val.toString().isEmpty) {
return "This field is required";
} else {
return null;
}
},
onChanged: (val) {
},
controller: _currentLocationController,
),
Text("Your location in India"),
TextFormField(
autovalidateMode: AutovalidateMode.onUserInteraction,
validator: (val) {
if (val.toString().isEmpty) {
return "This field is required";
} else {
return null;
}
},
onChanged: (val) {},
controller: _locationIndiaController,
),
const SizedBox(
height: 25,
),
Container(
width: double.infinity,
height: 45,
decoration: BoxDecoration(
color: btndisable ? Colors.blue : Colors.red,
borderRadius: BorderRadius.circular(8),
),
child: TextButton(
onPressed: (){
if(_formKey.currentState!.validate()){
Navigator.of(context).pushNamedAndRemoveUntil(
'HomeScreen', (Route<dynamic> route) => false);
}
}
child: Text("Continue"),
),
),
const SizedBox(
height: 20,
),
],
),
),
)),
);
}
Future<void> _selectDate(BuildContext context) async {
final DateTime? picked = await showDatePicker(
context: context,
initialDate: selectedDate,
firstDate: DateTime(1970),
lastDate: DateTime(2101));
if (picked != null && picked != selectedDate) {
setState(() {
selectedDate = picked;
_dobController.text =
"${selectedDate.day}/${selectedDate.month}/${selectedDate.year}";
});
}
}
void notdisbled() {
if (_formKey.currentState!.validate() == false) {
setState(() {
btndisable = false;
});
} else {
setState(() {
btndisable = true;
});
}
}
}
for disable the button change to this :
child: TextButton(
onPressed: _formKey.currentState != null && _formKey.currentState.validate() ? () {
Navigator.of(context).pushNamedAndRemoveUntil(
'HomeScreen', (Route<dynamic> route) => false);
}: null,
child: AppText(
text: "Continue",
fontSize: 16,
fontWeight: FontWeight.bold,
color: AppColor.white),
),
but when you use
formKey.currentState!.validate()
when you type any thing, flutter try call it every time so your form widget run all validator func in all its textfield. so it is natural for all textfield to get error message

type 'Null' is not a subtype of type 'File' of 'image' flutter problem

I uploaded my image to FireStore. When I am creating an image it's perfectly ok everything uploading perfectly. After SignUp I can easily go to the user profile and can see the user name and email. But when I log out from the user profile and from my LOGIN from when providing existing email and password which I have created already then the Exception is thrown. I am not getting the issue. Exception has occurred.
_TypeError (type 'Null' is not a subtype of type 'File' of 'image')
import 'dart:io';
import '../picker/user_image_picker.dart';
import 'package:flutter/material.dart';
class AuthForm extends StatefulWidget {
AuthForm(this.submitFn, this.isLoading);
final bool isLoading;
var submitFn;
void function(
String email,
String password,
String userName,
File image,
bool isLogin,
BuildContext ctx,
);
#override
_AuthFormState createState() => _AuthFormState();
#override
noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
class _AuthFormState extends State<AuthForm> {
final _formKey = GlobalKey<FormState>();
var _isLogin = true;
var _userEmail = '';
var _userName = '';
var _userPasssword = '';
File? userImageFile;
void pickedImage(File image) {
userImageFile = image;
}
void _trySubmit() {
final isValid = _formKey.currentState!.validate();
FocusScope.of(context).unfocus();
if (userImageFile == null && !_isLogin) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Please Pick an Image.'),
backgroundColor: Theme.of(context).errorColor,
),
);
return;
}
if (isValid) {
_formKey.currentState?.save();
print(_userEmail);
print(_userName);
print(_userPasssword);
print(' Good to go ');
widget.submitFn(
_userEmail.trim(),
_userPasssword.trim(),
_userName.trim(),
userImageFile,
_isLogin,
context,
);
} else {
print('Form is not valid');
}
}
#override
Widget build(BuildContext context) {
return Card(
margin: EdgeInsets.all(20),
child: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.all(16),
child: Form(
key: _formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
if (!_isLogin) UserImagePicker(pickedImage),//this is my image file
TextFormField(
key: ValueKey('email'),
onSaved: (value) {
_userEmail = value!;
},
validator: (value) {
if (value!.isEmpty ||
!value.contains(RegExp(
'^[a-zA-Z0-9+_.-]+#[a-zA-Z0-9.-]+.[a-z]+.[com]'))) {
return 'enter valid Email';
//print('Email validation is not ok');
} else {
return null;
}
},
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
labelText: 'Email Address', icon: Icon(Icons.email)),
),
if (!_isLogin)
TextFormField(
key: ValueKey('userName'),
onSaved: (value) {
_userName = value!;
},
validator: (value) {
if (value == null || value.length < 4) {
return 'Enter At least 4 charaters ';
}
return null;
},
decoration: InputDecoration(
labelText: 'User Name', icon: Icon(Icons.person)),
),
TextFormField(
key: ValueKey('password'),
onSaved: (value) {
_userPasssword = value!;
},
obscureText: true,
validator: (value) {
if (value == null || value.isEmpty || value.length < 7) {
return 'Enter at least 7 Digits';
}
return null;
},
decoration: InputDecoration(
labelText: 'Password',
icon: Icon(
Icons.security,
),
),
),
SizedBox(
height: 20,
),
if (widget.isLoading) CircularProgressIndicator(),
if (!widget.isLoading)
ElevatedButton(
child: Text(_isLogin ? 'Login' : 'Signup'),
onPressed: _trySubmit,
),
if (widget.isLoading) CircularProgressIndicator(),
if (!widget.isLoading)
TextButton(
style: TextButton.styleFrom(
primary: Theme.of(context).primaryColor,
),
child: Text(_isLogin
? 'Create New Account'
: 'I already have an account'),
onPressed: () {
setState(
() {
_isLogin = !_isLogin;
},
);
},
)
],
),
),
),
),
);
}
}
Looks like userImageFile is null. This happen because this variable is nullable, and when it gets passed to submitFn (which weirdly is a dynamic variable...?) it throws, because it expects a non-nullable image parameter.

Firebase Infinite Loading after Login/Register

so i am working on an app which uses firebase.
But I am having an issue although this has been solved that doesnt seem to help me. My loading screen goes to infinite loading after login/register.
Login Code
import 'package:flutter/material.dart';
import 'package:studo/services/auth.dart';
import 'package:studo/shared/constants.dart';
import 'package:studo/shared/loading.dart';
class SignIn extends StatefulWidget {
final Function toggleView;
SignIn({this.toggleView});
#override
_SignInState createState() => _SignInState();
}
class _SignInState extends State<SignIn> {
final AuthService _auth = AuthService();
final _formKey = GlobalKey<FormState>();
String error = '';
bool loading = false;
// text field state
String email = '';
String password = '';
#override
Widget build(BuildContext context) {
return loading
? Loading()
: Scaffold(
body: SingleChildScrollView(
child: Center(
child: Container(
padding:
EdgeInsets.symmetric(vertical: 20.0, horizontal: 50.0),
child: Form(
key: _formKey,
child: Column(
children: <Widget>[
SizedBox(height: 30.0),
CircleAvatar(
backgroundImage: AssetImage('assets/login.png'),
backgroundColor: Colors.transparent,
radius: 150,
),
TextFormField(
decoration: textInputDecoration.copyWith(
hintText: 'Email',
hintStyle: TextStyle(color: Colors.purple)),
validator: (val) =>
val.isEmpty ? 'Enter an email' : null,
onChanged: (val) {
setState(() => email = val);
},
),
SizedBox(height: 20.0),
TextFormField(
obscureText: true,
decoration: textInputDecoration.copyWith(
hintText: 'Password',
hintStyle: TextStyle(color: Colors.purple)),
validator: (val) => val.length < 6
? 'Enter a password 6+ chars long'
: null,
onChanged: (val) {
setState(() => password = val);
},
),
SizedBox(height: 20.0),
RaisedButton(
color: Colors.purple,
child: Text(
'Login',
style: TextStyle(color: Colors.white),
),
onPressed: () async {
if (_formKey.currentState.validate()) {
setState(() => loading = true);
dynamic result =
await _auth.signInWithEmailAndPassword(
email, password);
if (result == null) {
setState(() {
loading = false;
error =
'Could not sign in with those credentials';
});
}
}
}),
SizedBox(height: 12.0),
Text(
error,
style: TextStyle(color: Colors.red, fontSize: 14.0),
),
GestureDetector(
onTap: () {
Navigator.pushReplacementNamed(
context, '/register');
},
child: Text(
'Dont have an acoount Sign Up',
style: TextStyle(color: Colors.purple),
),
),
],
),
),
),
),
),
);
}
}
Loading.dart code
import 'package:flutter/material.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
class Loading extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
color: Colors.white,
child: Center(
child: Column(
children: [
SizedBox(height: 50,),
SpinKitChasingDots(
color: Colors.purple,
size: 50.0,
),
SizedBox(height: 70,),
Text('Please Exit the App and then Open Again Due to an issue. The Home Page will Load again',
style: TextStyle(fontSize: 10),
)
],
),
),
);
}
}
A help would be greatly appreciated.
i think i am wrong with the on pressed part but i cant possibly figure that out. PLease help me
In your onPressed you are only handling the result == null. You should also handle when you have a result, such that you can go to a next page when returned result is logged in, or set loading = false.
This can be done with an else statement, because if result != null you want to handle the result.
The result should be of the class UserCredential, which contains the User class.
It could be that the email or password is incorrect, you want to handle these cases as well, good practice is to do this in a try-catch block. Example from firebase
try {
UserCredential userCredential = await
FirebaseAuth.instance.signInWithEmailAndPassword(
email: "barry.allen#example.com",
password: "SuperSecretPassword!"
);
} on FirebaseAuthException catch (e) {
if (e.code == 'user-not-found') {
print('No user found for that email.');
} else if (e.code == 'wrong-password') {
print('Wrong password provided for that user.');
}
}
You've returned the loading screen only, so it will of course be in infinite loop. Return your Home page instead.

The property 'isEmpty" can't be unconditionally accessed because the receiver can be 'null'

import 'package:flutter/material.dart';
import 'package:flutter_app_1/utils/routes.dart';
class LoginPage extends StatefulWidget {
#override
_LoginPageState createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
String name = "";
bool changeButton = false;
final _formKey = GlobalKey<FormState>();
moveToHome(BuildContext context) async {
if (_formKey.currentState.validate()) {
setState(() {
changeButton = true;
});
await Future.delayed(Duration(seconds: 1));
await Navigator.pushNamed(context, MyRoutes.homeRoute);
setState(() {
changeButton = false;
});
}
}
#override
Widget build(BuildContext context) {
return Material(
color: Colors.white,
child: SingleChildScrollView(
child: Form(
key: _formKey,
child: Column(
children: [
Image.asset(
"assets/images/login_image.png",
fit: BoxFit.cover,
height: 500,
),
SizedBox(
height: 20.0,
),
Text(
"Welcome $name",
style: TextStyle(fontSize: 22, fontWeight: FontWeight.bold),
),
SizedBox(
height: 28.0,
),
Padding(
padding: const EdgeInsets.symmetric(
vertical: 16.0, horizontal: 32.0),
child: Column(
children: [
TextFormField(
decoration: InputDecoration(
hintText: "Enter User Name",
labelText: "Username",
),
validator: (String? value) {
if (value != null && value.isEmpty) {
return "Username can't be empty";
}
return null;
},
onChanged: (value) {
name = value;
setState(() {});
},
),
TextFormField(
obscureText: true,
decoration: InputDecoration(
hintText: "Enter password",
labelText: "Password",
),
validator: (String? value) {
if (value != null && value.isEmpty) {
return "Password can't be empty";
}
return null;
},
),
SizedBox(
height: 40.0,
),
Material(
color: Colors.deepPurple,
borderRadius:
BorderRadius.circular(changeButton ? 50 : 8),
child: InkWell(
onTap: () => moveToHome(context),
child: AnimatedContainer(
duration: Duration(seconds: 1),
width: changeButton ? 50 : 150,
height: 50,
//color: Colors.deepPurple,
alignment: Alignment.center,
child: changeButton
? Icon(
Icons.done,
color: Colors.white,
)
: Text(
"Login",
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 18),
),
// decoration: BoxDecoration(
// //color: Colors.deepPurple,
// // shape: changeButton
// // ? BoxShape.circle
// // : BoxShape.rectangle,
// ),
),
),
),
// ElevatedButton(
// child: Text("Login"),
// style: TextButton.styleFrom(minimumSize: Size(150, 40)),
// onPressed: () {
// Navigator.pushNamed(context, MyRoutes.homeRoute);
// })
],
),
)
],
),
),
));
}
}
Hi All,
I'm trying to add validator to widget but I'm getting this error please help. to solve this error.
The Error:
The method 'validate' can't be unconditionally invoked because the receiver can be 'null'. Try making the call conditional (using '?.') or adding a null check to the target ('!')
I tried replacing the code provided and still I'm getting the error. please look into it.
Second Error:
The method 'validate' can't be unconditionally invoked because the receiver can be 'null'. Try making the call conditional (using '?.') or adding a null check to the target ('!')
I tried replacing the code provided and still I'm getting the error. please look into it.
You need to make the code null safe, to do that you have a few options, depending on what values you expect.
If you want a String value only then set the initialValue to '' and update the validator condition to (value!.isEmpty) add an ! after value.
If the value really can be null, then add a test to ensure that members are only accessed when the value isn’t null, that is if initialValue is set to null, then you would need to update validator to check for null.
validator: (String? value) {
if (value != null && value.isEmpty) {
return "Username can't be empty";
}
return null;
}
If you want to know more about null-safety in dart check the official docs
The error you're facing came from null-safety, the value that you're getting from the validator method can be either null or either a String, so you may want to update your code to this example:
validator: (String? value) {
if (value!.isEmpty) {
return "Username cann't be empty";
}
return null;
}
You can learn more about null safety on official documentation:
https://dart.dev/null-safety