I'm trying to get info from my db using http get method, but when I try to get data, it returns the error:
E/flutter (15407): [ERROR:flutter/lib/ui/ui_dart_state.cc(198)] Unhandled Exception: type 'String' is not a subtype of type 'int' of 'index'
Here is the code:
// ignore_for_file: no_leading_underscores_for_local_identifiers, prefer_typing_uninitialized_variables
import 'dart:convert';
import 'package:apetit_project/models/app_user.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import '../models/auth_form_data.dart';
import 'package:http/http.dart' as http;
class AuthForm extends StatefulWidget {
final void Function(AuthFormData) onSubmit;
const AuthForm({
Key? key,
required this.onSubmit,
}) : super(key: key);
#override
State<AuthForm> createState() => _AuthFormState();
}
class _AuthFormState extends State<AuthForm> {
TextEditingController _emailController = TextEditingController();
TextEditingController _passwordController = TextEditingController();
final _formKey = GlobalKey<FormState>();
final _formData = AuthFormData();
String _teste = '[]';
final _url = 'http://172.16.30.120:8080/ords/apiteste/integrafoods/users';
#override
void dispose() {
_emailController.dispose();
_passwordController.dispose();
super.dispose();
}
bool isLogin = true;
late String title;
late String actionButton;
late String toggleButton;
void _submit() {
final isValid = _formKey.currentState?.validate() ?? false;
if (!isValid) return;
widget.onSubmit(_formData);
}
Future<void> _loadUsers() async {
final response = await http.get(Uri.parse(_url));
Map<String, dynamic> data = jsonDecode(response.body);
data.forEach(
(userId, userData) {
_teste = userData['nome'];
},
);
print(_teste);
// $_url/${newComment.comment}
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/images/Login.png'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
),
child: Container(
margin: const EdgeInsets.only(bottom: 30),
child: Padding(
padding: const EdgeInsets.all(20),
child: Form(
key: _formKey,
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
if (_formData.isSignup)
TextFormField(
key: const ValueKey('Nome'),
initialValue: _formData.name,
onChanged: (name) => _formData.name = name,
decoration: InputDecoration(
enabledBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Colors.black),
borderRadius: BorderRadius.circular(30)),
focusedBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Colors.black),
borderRadius: BorderRadius.circular(30)),
focusedErrorBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Colors.black),
borderRadius: BorderRadius.circular(30)),
labelText: 'Nome',
labelStyle: const TextStyle(color: Colors.black),
),
keyboardType: TextInputType.emailAddress,
),
if (_formData.isLogin)
TextFormField(
// controller: _emailController,
key: const ValueKey('Email'),
initialValue: _formData.email,
onChanged: (email) => _formData.email = email,
decoration: InputDecoration(
enabledBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Colors.black),
borderRadius: BorderRadius.circular(30)),
focusedBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Colors.black),
borderRadius: BorderRadius.circular(30)),
focusedErrorBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Colors.black),
borderRadius: BorderRadius.circular(30)),
prefixIcon: Image.asset(
'assets/images/email_icon.png',
scale: 6,
color: Colors.black,
),
labelText: 'Email',
labelStyle: const TextStyle(color: Colors.black),
),
validator: (_email) {
final email = _email ?? '';
if (!email.contains('#')) {
return 'E-mail informado não é válido.';
}
return null;
},
keyboardType: TextInputType.emailAddress,
),
const SizedBox(
height: 20,
),
if (_formData.isLogin)
TextFormField(
// controller: _passwordController,
key: const ValueKey('password'),
initialValue: _formData.password,
onChanged: (password) => _formData.password = password,
style: const TextStyle(color: Colors.black),
obscureText: true,
decoration: InputDecoration(
enabledBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Colors.black),
borderRadius: BorderRadius.circular(30)),
focusedBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Colors.black),
borderRadius: BorderRadius.circular(30)),
errorBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Colors.black),
borderRadius: BorderRadius.circular(30)),
focusedErrorBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Colors.black),
borderRadius: BorderRadius.circular(30)),
prefixIcon: Padding(
padding: const EdgeInsets.only(left: 18, right: 18),
child: Image.asset(
'assets/images/password_icon.png',
scale: 6,
color: Colors.black,
),
),
labelText: 'Senha',
labelStyle: const TextStyle(color: Colors.black)),
validator: (_password) {
final password = _password ?? '';
if (password.length < 6) {
return 'Senha deve ter no mínimo 6 caracteres';
}
return null;
},
),
const SizedBox(
height: 20,
),
SizedBox(
width: double.infinity,
child: ElevatedButton(
// onPressed: _signInUser,
onPressed: _loadUsers,
style: ButtonStyle(
shape: MaterialStateProperty.all(RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30),
)),
padding:
MaterialStateProperty.all(const EdgeInsets.all(15)),
backgroundColor: MaterialStateProperty.all(
Theme.of(context).colorScheme.secondary),
),
child: Text(
_formData.isLogin ? 'Entrar' : 'Cadastrar',
style: const TextStyle(
color: Colors.black,
fontFamily: 'Raleway',
fontWeight: FontWeight.bold),
),
),
),
TextButton(
onPressed: () {
setState(() {
_formData.toggleAuthMode();
});
},
child: Text(
_formData.isLogin
? 'Criar uma nova conta?'
: 'Já possui conta?',
),
),
],
),
),
),
),
),
);
}
Future _signInUser() async {
await FirebaseAuth.instance.signInWithEmailAndPassword(
email: _emailController.text,
password: _passwordController.text,
);
}
}
{
"items": [
{
"id": 1,
"login": "1234567",
"nome": "Ricardo",
"situacao": "A",
"telefone": "(14) 99797-5621",
"senha": "124578",
"dt_inclusao": null,
"usu_inclusao": null,
"dt_alteracao": null,
"usu_alteracao": null
}
],
"hasMore": false,
"limit": 25,
"offset": 0,
"count": 1,
"links": [
{
"rel": "self",
"href": "http://172.16.30.120:8080/ords/apiteste/integrafoods/users"
},
{
"rel": "describedby",
"href": "http://172.16.30.120:8080/ords/apiteste/metadata-catalog/integrafoods/item"
},
{
"rel": "first",
"href": "http://172.16.30.120:8080/ords/apiteste/integrafoods/users"
}
]
}
I added the full widget code and the JSON. I am seeking a working example so I can understand why it's not working.
It's look like you have in userDat variable some sort of List. It dosen't have key:value pair like Map. Yo need to run through List indexes.
Try to use
_teste = userData[0]['nome'];
And look what happens.
You need to look on JSON structure you receive from the server. If you show here JSON structure it will help to find right solution for you.
Related
I want to send post request to this api:
Here is the sample bearer token :
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjY3MjMzNjEzLCJpYXQiOjE2NjcxNDcyMTMsImp0aSI6IjgyNDg0YWYzMDdmOTQ0YjNhMTQ5ZWIzN2NkNjIzNGI4IiwiaWQiOjV9.qc9fmF4B0V6NTwxsztBb6AkF78kU_06wommCa5gLgOo
What I tried:
Here Is my Controller for the API:
Future<bool> createDisplay(
String name, String category, String templateName, int productId) async {
var url = Uri.parse(
"https://digital-display.betafore.com/api/v1/digital-display/displays/");
var token = localStorage.getItem('access');
try {
var formdata = new Map<String, dynamic>();
formdata["name"] = name;
formdata["category"] = category;
formdata["template_name"] = templateName;
formdata["products"] = productId;
http.Response response =
await http.post(url, body: json.encode(formdata), headers: {
"Content-Type": "application/json",
'Authorization':
'Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjY3MjMzNjEzLCJpYXQiOjE2NjcxNDcyMTMsImp0aSI6IjgyNDg0YWYzMDdmOTQ0YjNhMTQ5ZWIzN2NkNjIzNGI4IiwiaWQiOjV9.qc9fmF4B0V6NTwxsztBb6AkF78kU_06wommCa5gLgOo'
});
Future.error(response.body);
var data = json.encode(response.body) as Map;
if (response.statusCode == 200) {
print(response.body);
return Future.error("Its working");
} else {
return Future.error("Code Proble");
}
} catch (exception) {
Future.error("Something is wrong with the codes");
return false;
}
}
Here is the front end code where I tried to send post request using textformfield.
import 'package:digitaldisplay/controllers/DisplayController.dart';
import 'package:digitaldisplay/views/widgets/Display.dart';
import 'package:digitaldisplay/views/widgets/ProductDisplayCard.dart';
import 'package:flutter/material.dart';
import 'package:flutter/src/widgets/container.dart';
import 'package:flutter/src/widgets/framework.dart';
import 'package:provider/provider.dart';
class CreateDisplay extends StatefulWidget {
const CreateDisplay({super.key});
static const routeName = "/create-display";
#override
State<CreateDisplay> createState() => _CreateDisplayState();
}
class _CreateDisplayState extends State<CreateDisplay> {
String _name = "";
String _category = "";
String _templateName = "";
late final int _product;
// String catelogImage = "";
// String video = "";
//String productId = "";
final _form = GlobalKey<FormState>();
void _addDisplay() async {
var isValid = _form.currentState!.validate();
if (!isValid) {
return;
}
_form.currentState!.save();
bool create = await Provider.of<DisplayController>(context, listen: false)
.createDisplay(_name, _category, _templateName, _product);
if (create) {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text("Created"),
actions: [
ElevatedButton(
child: const Text("Return"),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
});
} else {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text("Failed to create display!"),
actions: [
ElevatedButton(
child: const Text("Return"),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
});
}
}
child: Form(
key: _form,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Flexible(
child: Padding(
padding: EdgeInsets.all(10),
child: TextFormField(
validator: (v) {
if (v!.isEmpty) {
return "Please Enter a valid name";
} else {
return null;
}
},
onSaved: (value) {
_name = value as String;
},
autofocus: true,
style: const TextStyle(
fontSize: 15.0, color: Colors.black),
decoration: InputDecoration(
border: InputBorder.none,
hintText: 'Name',
filled: true,
fillColor: Colors.white,
contentPadding: const EdgeInsets.only(
left: 14.0, bottom: 6.0, top: 8.0),
focusedBorder: OutlineInputBorder(
borderSide: const BorderSide(
color: Color.fromARGB(255, 73, 57, 55)),
borderRadius: BorderRadius.circular(0.0),
),
enabledBorder: UnderlineInputBorder(
borderSide:
const BorderSide(color: Colors.grey),
borderRadius: BorderRadius.circular(0.0),
),
),
),
),
),
Flexible(
child: Padding(
padding: EdgeInsets.all(10),
child: TextFormField(
validator: (v) {
if (v!.isEmpty) {
return "Please enter valid category title";
} else {
return null;
}
},
onSaved: (value) {
_category = value as String;
},
autofocus: true,
style: const TextStyle(
fontSize: 15.0, color: Colors.black),
decoration: InputDecoration(
border: InputBorder.none,
hintText: 'Category',
filled: true,
fillColor: Colors.white,
contentPadding: const EdgeInsets.only(
left: 14.0, bottom: 6.0, top: 8.0),
focusedBorder: OutlineInputBorder(
borderSide: const BorderSide(
color: Color.fromARGB(255, 73, 57, 55)),
borderRadius: BorderRadius.circular(0.0),
),
enabledBorder: UnderlineInputBorder(
borderSide:
const BorderSide(color: Colors.grey),
borderRadius: BorderRadius.circular(0.0),
),
),
),
),
),
Flexible(
child: Padding(
padding: EdgeInsets.all(10),
child: TextFormField(
validator: (v) {
if (v!.isEmpty) {
return "Please enter valid template name";
} else {
return null;
}
},
onSaved: (value) {
_templateName = value as String;
},
autofocus: true,
style: const TextStyle(
fontSize: 15.0, color: Colors.black),
decoration: InputDecoration(
border: InputBorder.none,
hintText: 'Template Name',
filled: true,
fillColor: Colors.white,
contentPadding: const EdgeInsets.only(
left: 14.0, bottom: 6.0, top: 8.0),
focusedBorder: OutlineInputBorder(
borderSide: const BorderSide(
color: Color.fromARGB(255, 73, 57, 55)),
borderRadius: BorderRadius.circular(0.0),
),
enabledBorder: UnderlineInputBorder(
borderSide:
const BorderSide(color: Colors.grey),
borderRadius: BorderRadius.circular(0.0),
),
),
),
),
),
Flexible(
child: Padding(
padding: EdgeInsets.all(10),
child: TextFormField(
keyboardType: TextInputType.number,
validator: (v) {
if (v!.isEmpty) {
return "Please enter valid product Id";
} else {
return null;
}
},
onSaved: (value) {
_product = int.tryParse(value!) ?? 0;
},
autofocus: true,
style: const TextStyle(
fontSize: 15.0, color: Colors.black),
decoration: InputDecoration(
border: InputBorder.none,
hintText: 'Product Id',
filled: true,
fillColor: Colors.white,
contentPadding: const EdgeInsets.only(
left: 14.0, bottom: 6.0, top: 8.0),
focusedBorder: OutlineInputBorder(
borderSide: const BorderSide(
color: Color.fromARGB(255, 73, 57, 55)),
borderRadius: BorderRadius.circular(0.0),
),
enabledBorder: UnderlineInputBorder(
borderSide:
const BorderSide(color: Colors.grey),
borderRadius: BorderRadius.circular(0.0),
),
),
),
),
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Flexible(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: ElevatedButton(
onPressed: () {
_addDisplay();
},
child: Text("Add Display"),
style: buttonStyle2,
),
),
),
],
),
],
I only added the code of my frontend where I tried to pass the value. But Can't post data. I am getting an error also. The error is:
{"status":"error","message":{"products":["Expected a list of items but got type \"int\"."]}}
When I send data using postman It works perfectly. I think its for formdata though I am not sure about it. Is there any solution for this issue?
It says it in the error there. "Expected a list of items but got type "int" In your post you are putting productId which is an int in the "products". The backend is looking for a list of products here. You can try
formdata["products"] = [productId];
to see what you come up with. I don't know what the backend is looking for in terms of the products list though. It is strange that the post with an int works in Postman too.
I'm building a form for shipping and am able to add as many items as possible. (Adding a Widget in a ListView every time a button is pressed)
My question is, once the form widgets are created and filled, how do I get the information from each TextFormField in each Widget?
Once the information is retrieved I will send it to Firebase.
Here's the code I Have:
import 'package:flutter/material.dart';
import 'package:flutter_login_test/helpers/constants.dart';
class AddItemsToRequest extends StatefulWidget {
const AddItemsToRequest({Key? key}) : super(key: key);
#override
State<AddItemsToRequest> createState() => _AddItemsToRequestState();
}
class _AddItemsToRequestState extends State<AddItemsToRequest> {
List<TextEditingController> controllers = [];
List<Widget> fields = [];
RegExp regExp = RegExp('[aA-zZ]');
int quantity = 0;
double weight = 0;
double height = 0;
Widget itemForm() {
return Column(children: [
Container(
decoration:
BoxDecoration(color: grey, border: Border.all(color: black)),
width: double.infinity,
child: const Center(
child: Text('Package details',
style: TextStyle(
fontWeight: FontWeight.bold,
backgroundColor: grey,
fontSize: 24)),
)),
Row(
children: [
Flexible(
child: TextFormField(
onChanged: (value) {
quantity = value as int;
},
keyboardType: TextInputType.number,
validator: (value) => value!.isEmpty || value is int
? 'Quantity cannot be empty'
: null,
autovalidateMode: AutovalidateMode.onUserInteraction,
decoration: const InputDecoration(
errorStyle: TextStyle(color: Colors.redAccent),
border: OutlineInputBorder(
borderSide: BorderSide(),
borderRadius: BorderRadius.all(
Radius.circular(0.0),
),
),
fillColor: Color.fromARGB(255, 238, 238, 238),
filled: true,
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.blueAccent, width: 2.5),
),
hintText: "Quantity : "),
),
),
Flexible(
child: TextFormField(
onChanged: (value) {
weight = value as double;
},
keyboardType: TextInputType.number,
validator: (value) => value!.isEmpty || regExp.hasMatch(value)
? 'Weight cannot be empty'
: null,
autovalidateMode: AutovalidateMode.onUserInteraction,
decoration: const InputDecoration(
errorStyle: TextStyle(color: Colors.redAccent),
border: OutlineInputBorder(
borderSide: BorderSide(),
borderRadius: BorderRadius.all(
Radius.circular(0.0),
),
),
fillColor: Color.fromARGB(255, 238, 238, 238),
filled: true,
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.blueAccent, width: 2.5),
),
hintText: "Weight : "),
),
),
Flexible(
child: TextFormField(
onChanged: (value) {
height = value;
},
validator: (value) => value!.isEmpty ? 'Height cannot be empty' : null,
autovalidateMode: AutovalidateMode.onUserInteraction,
decoration: const InputDecoration(
errorStyle: TextStyle(color: Colors.redAccent),
border: OutlineInputBorder(
borderSide: BorderSide(),
borderRadius: BorderRadius.all(
Radius.circular(0.0),
),
),
fillColor: Color.fromARGB(255, 238, 238, 238),
filled: true,
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.blueAccent, width: 2.5),
),
hintText: "Height : "),
),
),
],
),
]);
}
Widget _addTile() {
return ElevatedButton(
child: const Icon(Icons.add),
onPressed: () async {
final controller = TextEditingController();
final field = itemForm();
setState(() {
controllers.add(controller);
fields.add(field);
});
});
}
Widget _listView() {
return ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: fields.length,
itemBuilder: (context, index) {
final item = fields[index];
return Dismissible(
key: ObjectKey(item),
onDismissed: (direction) {
// Remove the item from the data source.
setState(() {
fields.removeAt(index);
});
ScaffoldMessenger.of(context)
.showSnackBar(const SnackBar(content: Text('Package removed')));
},
background: Container(
color: const Color.fromARGB(255, 210, 31, 19),
child: const Center(
child: Text(
'Remove ',
style: TextStyle(
color: white, fontWeight: FontWeight.bold, fontSize: 32),
),
)),
child: Container(
width: double.infinity,
margin: const EdgeInsets.all(5),
child: fields[index],
),
);
},
);
}
Widget _okButton() {
return ElevatedButton(
onPressed: () {
for (var element in fields) {
print(quantity);
}
Navigator.of(context).pop();
print('ok');
},
child: const Text("OK"),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(backgroundColor: blue),
body: Column(
mainAxisSize: MainAxisSize.max,
children: [
Flexible(child: _addTile()),
SizedBox(
height: MediaQuery.of(context).size.height - 200,
child: _listView()),
Flexible(child: _okButton()),
],
),
);
}
}
I think you are expecting this answer. iterate your list of texteditingcontroller and get the text stored in that controllers one by one.
for (int i = 0; i < controllers.length; i++) {
var data = controllers[i].text;
//print or add data to any other list and insert to another list and save to database
}
I'm trying to create a validator that won't allow user to login if it's e-mail doesn't exists at my "user" table. I've tried to say that if it returns an empty list from get method than it doesn't allow the user to login.
I've tried this way:
final _formData = AuthFormData();
List<UserData> _teste = [];
List<UserData> get teste => [..._teste];
Future<void> _loadUsers() async {
final response = await http.get(
Uri.parse((isLogin)
? 'http://999.99.99.999:9999/ords/apiteste/integrafoods/users_login/${_formData.email}'
: 'http://999.99.99.999:9999/ords/apiteste/integrafoods/users_register/${_formData.empNo}'),
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
);
if (response.body == 'null') return;
final data = jsonDecode(response.body)['items'] as List?;
if (data != null) {
_teste = data.map((e) => UserData.fromMap(e)).toList();
}
print(data);
}
Future<void> _submit() async {
// if (isLogin) {
// final isValid1 = _formKey.currentState?.validate() ?? false;
// if (!isValid1) return;
// }
await _loadUsers();
final isValid = _formKey.currentState?.validate() ?? false;
if (!isValid) return;
widget.onSubmit(_formData);
}
}
Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(30)),
child: TextFormField(
// controller: _emailController,
key: const ValueKey('Email'),
initialValue: _formData.email,
onChanged: (email) => _formData.email = email,
decoration: InputDecoration(
enabledBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Colors.black),
borderRadius: BorderRadius.circular(30)),
focusedBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Colors.black),
borderRadius: BorderRadius.circular(30)),
errorBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Colors.red),
borderRadius: BorderRadius.circular(30)),
focusedErrorBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Colors.red),
borderRadius: BorderRadius.circular(30)),
prefixIcon: Image.asset(
'assets/images/email_icon.png',
scale: 6,
color: Colors.black,
),
labelText: 'Email',
labelStyle: const TextStyle(color: Colors.black),
),
validator: (_email) {
final email = _email ?? '';
if (isLogin && _items == []) {
// <- Here
return 'Usuário não cadastrado'; // <- Here
}
return null;
},
keyboardType: TextInputType.emailAddress,
),
),
SizedBox(
width: double.infinity,
child: ElevatedButton(
// onPressed: _signInUser,
onPressed: () {
// _loadUsers();
_submit();
},
style: ButtonStyle(
shape: MaterialStateProperty.all(RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30),
)),
padding:
MaterialStateProperty.all(const EdgeInsets.all(15)),
backgroundColor: MaterialStateProperty.all(
Theme.of(context).colorScheme.secondary),
),
child: Text(
_formData.isLogin ? 'Entrar' : 'Cadastrar',
style: const TextStyle(
color: Colors.black,
fontFamily: 'Raleway',
fontWeight: FontWeight.bold),
),
),
),
But when I run the code this validator just doesn't work and I can login even with an e-mail that doesn't exist in the database. What can I try to resolve this?
I have a List of items that I retrieve from a database with http.get method. I need to create a validator that only allow users to submit if the value typed is equal to at least one of the values of the list.
Example: The list is: [{name: Peter, email: peter#gmail.com}{name: Mathew, email: mtw#gmail.com}]. Then I have two textFormFields, one for NAME and another for EMAIL. So if the NAME and EMAIL the user types match any of the items of the list, than user can submit. I created the http.get method and I created the TextFormfields, but I cannot figure how to create the validator.
Here is the Formulary code:
// ignore_for_file: no_leading_underscores_for_local_identifiers, prefer_typing_uninitialized_variables
import 'dart:convert';
import 'package:apetit_project/components/teste_app_users_item.dart';
import 'package:apetit_project/models/app_user.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import '../models/auth_form_data.dart';
import 'package:http/http.dart' as http;
import '../models/user_data.dart';
class AuthForm extends StatefulWidget {
final void Function(AuthFormData) onSubmit;
const AuthForm({
Key? key,
required this.onSubmit,
}) : super(key: key);
#override
State<AuthForm> createState() => _AuthFormState();
}
class _AuthFormState extends State<AuthForm> {
TextEditingController _emailController = TextEditingController();
TextEditingController _passwordController = TextEditingController();
final _formKey = GlobalKey<FormState>();
final _formData = AuthFormData();
List<dynamic> _teste = [];
List<dynamic> get teste => [..._teste];
final _url = 'URL';
#override
void dispose() {
_emailController.dispose();
_passwordController.dispose();
super.dispose();
}
bool isLogin = true;
late String title;
late String actionButton;
late String toggleButton;
void _submit() {
final isValid = _formKey.currentState?.validate() ?? false;
if (!isValid) return;
widget.onSubmit(_formData);
}
Future<void> _loadUsers() async {
final response = await http.get(
Uri.parse('http://172.16.30.120:8080/ords/apiteste/integrafoods/users'),
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
);
if (response.body == 'null') return;
final data = jsonDecode(response.body)['items'] as List?;
if (data != null) {
// _teste = data;
_teste = data.map((e) => MyItem.fromMap(e)).toList();
print(data);
}
// print(_teste.toList());
}
#override
_initState() {
_loadUsers();
super.initState();
}
#override
Widget build(BuildContext context) {
// print(_teste);
return Scaffold(
body: Container(
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/images/Login.png'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
),
child: Container(
margin: const EdgeInsets.only(bottom: 20),
child: Padding(
padding: const EdgeInsets.all(20),
child: Form(
key: _formKey,
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
if (_formData.isSignup)
TextFormField(
key: const ValueKey('Nome'),
initialValue: _formData.name,
onChanged: (name) => _formData.name = name,
decoration: InputDecoration(
enabledBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Colors.black),
borderRadius: BorderRadius.circular(30)),
focusedBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Colors.black),
borderRadius: BorderRadius.circular(30)),
focusedErrorBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Colors.black),
borderRadius: BorderRadius.circular(30)),
prefixIcon: Padding(
padding: const EdgeInsets.only(left: 18, right: 18),
child: Image.asset(
'assets/images/password_icon.png',
scale: 6,
color: Colors.black,
),
),
labelText: 'Nome',
labelStyle: const TextStyle(color: Colors.black),
),
keyboardType: TextInputType.emailAddress,
),
const SizedBox(
height: 4,
),
TextFormField(
// controller: _emailController,
key: const ValueKey('Email'),
initialValue: _formData.email,
onChanged: (email) => _formData.email = email,
decoration: InputDecoration(
enabledBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Colors.black),
borderRadius: BorderRadius.circular(30)),
focusedBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Colors.black),
borderRadius: BorderRadius.circular(30)),
focusedErrorBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Colors.black),
borderRadius: BorderRadius.circular(30)),
prefixIcon: Image.asset(
'assets/images/email_icon.png',
scale: 6,
color: Colors.black,
),
labelText: 'Email',
labelStyle: const TextStyle(color: Colors.black),
),
validator: (_email) {
final email = _email ?? '';
if (!email.contains('#')) {
return 'E-mail informado não é válido.';
}
return null;
},
keyboardType: TextInputType.emailAddress,
),
const SizedBox(
height: 4,
),
TextFormField(
// controller: _passwordController,
key: const ValueKey('password'),
initialValue: _formData.password,
onChanged: (password) => _formData.password = password,
style: const TextStyle(color: Colors.black),
obscureText: true,
decoration: InputDecoration(
enabledBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Colors.black),
borderRadius: BorderRadius.circular(30)),
focusedBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Colors.black),
borderRadius: BorderRadius.circular(30)),
errorBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Colors.black),
borderRadius: BorderRadius.circular(30)),
focusedErrorBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Colors.black),
borderRadius: BorderRadius.circular(30)),
prefixIcon: Padding(
padding: const EdgeInsets.only(left: 18, right: 18),
child: Image.asset(
'assets/images/password_icon.png',
scale: 6,
color: Colors.black,
),
),
labelText: 'Senha',
labelStyle: const TextStyle(color: Colors.black)),
validator: (_password) {
final password = _password ?? '';
if (password.length < 6) {
return 'Senha deve ter no mínimo 6 caracteres';
}
return null;
},
),
const SizedBox(
height: 10,
),
ElevatedButton(
onPressed: _loadUsers,
child: Text('teste'),
),
// Expanded(
// child: ListView.builder(
// itemBuilder: (ctx, index) {
// return Card(
// child: ClipRRect(child: MyItemItem(_teste[index])));
// },
// itemCount: _teste.length,
// ),
// ),
SizedBox(
width: double.infinity,
child: ElevatedButton(
// onPressed: _signInUser,
onPressed: _submit,
style: ButtonStyle(
shape: MaterialStateProperty.all(RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30),
)),
padding:
MaterialStateProperty.all(const EdgeInsets.all(15)),
backgroundColor: MaterialStateProperty.all(
Theme.of(context).colorScheme.secondary),
),
child: Text(
_formData.isLogin ? 'Entrar' : 'Cadastrar',
style: const TextStyle(
color: Colors.black,
fontFamily: 'Raleway',
fontWeight: FontWeight.bold),
),
),
),
TextButton(
onPressed: () {
setState(() {
_formData.toggleAuthMode();
});
},
child: Text(
_formData.isLogin
? 'Criar uma nova conta?'
: 'Já possui conta?',
),
),
],
),
),
),
),
),
);
}
// Future _signInUser() async {
// await FirebaseAuth.instance.signInWithEmailAndPassword(
// email: _emailController.text,
// password: _passwordController.text,
// );
// }
}
and here is the "My item" class
import 'dart:convert';
class MyItem {
final int id;
final String email;
final String? cpf;
MyItem({
required this.id,
required this.email,
required this.cpf,
});
Map<String, dynamic> toMap() {
final result = <String, dynamic>{};
result.addAll({'sequencia': id});
if (email != null) {
result.addAll({'email': email});
}
if (cpf != null) {
result.addAll({'cpf': cpf});
}
return result;
}
factory MyItem.fromMap(Map<String, dynamic> map) {
return MyItem(
id: int.tryParse(map['sequencia'].toString()) ?? 0,
email: map['email'],
cpf: map['cpf'],
);
}
String toJson() => json.encode(toMap());
factory MyItem.fromJson(String source) => MyItem.fromMap(json.decode(source));
}
How can I fix it?
The following should do the trick. Do the same for name and you're good to go.
validator: (_email) {
final email = _email ?? '';
if (!email.contains('#')) {
return 'E-mail informado não é válido.';
}
if (!_teste.any((item) => item.email == email)) { // <- Here
return 'E-mail já cadastrado.'; // <- Here
}
return null;
},
How to separate suffixIcon for password visibility? If I press icon on field password it also does the same thing on field confirm password.
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
bool isObsecure = false;
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: AppBar(
title: const Text('Text Form Field'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextFormField(
obscureText: isObsecure,
decoration: InputDecoration(
hintText: 'Password',
suffixIcon: IconButton(
onPressed: () {
setState(() {
isObsecure = !isObsecure;
});
},
icon: Icon(
isObsecure ? Icons.visibility_off : Icons.visibility,
),
),
),
),
TextFormField(
obscureText: isObsecure,
decoration: InputDecoration(
hintText: 'Confirm Password',
suffixIcon: IconButton(
onPressed: () {
setState(() {
isObsecure = !isObsecure;
});
},
icon: Icon(
isObsecure ? Icons.visibility_off : Icons.visibility,
),
),
),
),
],
),
),
),
);
}
}
you have to define 2 flags. 1 for password visibility and 1 for confirm:
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
bool isObsecure = false;
bool isConfirmObsecure = false;
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: AppBar(
title: const Text('Text Form Field'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextFormField(
obscureText: isObsecure,
decoration: InputDecoration(
hintText: 'Password',
suffixIcon: IconButton(
onPressed: () {
setState(() {
isObsecure = !isObsecure;
});
},
icon: Icon(
isObsecure ? Icons.visibility_off : Icons.visibility,
),
),
),
),
TextFormField(
obscureText: isConfirmObsecure,
decoration: InputDecoration(
hintText: 'Confirm Password',
suffixIcon: IconButton(
onPressed: () {
setState(() {
isConfirmObsecure = !isConfirmObsecure;
});
},
icon: Icon(
isConfirmObsecure
? Icons.visibility_off
: Icons.visibility,
),
),
),
),
],
),
),
),
);
}
}
///You can use the provider also to hide and visible the password icon. Hope this will work for you.
////This is my forgot password screen
import 'package:flutter/material.dart';
import 'package:form_field_validator/form_field_validator.dart';
import 'package:provider/provider.dart';
import 'package:traveling/Provider/common/ObscureTextState.dart';
import 'package:traveling/helpers/AppColors.dart';
import 'package:traveling/helpers/AppStrings.dart';
import 'package:traveling/screens/Employee/home/BottomNavBar.dart';
class ForgotPasswordA extends StatefulWidget {
#override
_ForgotPasswordAState createState() => _ForgotPasswordAState();
}
class _ForgotPasswordAState extends State<ForgotPasswordA> {
/// These variables are used for getting screen height and width
double? _height;
double? _width;
///controllers are used to get text which user enter in TextFiled
TextEditingController confirmPasswordController = TextEditingController();
TextEditingController passwordController = TextEditingController();
GlobalKey<FormState> _formkey = GlobalKey();
String? confirmPassword, password;
#override
void initState() {
// TODO: implement initState
super.initState();
}
///this widget is the main widget and it is used for building a UI in the app
#override
Widget build(BuildContext context) {
_height = MediaQuery.of(context).size.height;
_width = MediaQuery.of(context).size.width;
return Material(
child: Scaffold(
backgroundColor: AppColors.white,
body:Consumer<LoginProvider>(
builder:(context, obs, child) {
///Consumer is used to get value from the loginProvider class
return GestureDetector(
onTap: () {
FocusScope.of(context).unfocus();
},
child: Container(
height: _height,
width: _width,
margin: EdgeInsets.only(top: 70),
padding: EdgeInsets.only(bottom: 5),
child: SingleChildScrollView(
child: Column(
children: <Widget>[
SizedBox(height: _height! / 22),
appText(),
SizedBox(height: _height! / 18),
Container(
width: _width! * .85,
child: Form(
///define global key for validation
key: _formkey,
autovalidateMode: AutovalidateMode.onUserInteraction,
child: Column(
children: <Widget>[
SizedBox(height: _height! / 50),
TextFormField(
controller: passwordController,
validator: (value) {
if (value!.isEmpty) {
return "Please Enter Password!";
} else if (value.length < 6) {
return "Please Enter more than 6 digit .";
} else {
return null;
}
},
obscureText:
Provider.of<LoginProvider>(context, listen: false)
.isTrue,
keyboardType: TextInputType.emailAddress,
autofillHints: [AutofillHints.email],
cursorColor: AppColors.black,
style: TextStyle(
color: Color(0xff919AAA),
),
decoration: InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(25.0),
borderSide: BorderSide(
color: AppColors.textFieldColor,
),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(25.0),
borderSide: BorderSide(
color: AppColors.textFieldColor,
),
),
errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(25.0),
borderSide: BorderSide(
color: AppColors.red,
),
),
focusedErrorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(25.0),
borderSide: BorderSide(
color: AppColors.red,
),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(25.0),
borderSide: BorderSide(
color: AppColors.textFieldColor,
),
),
floatingLabelBehavior: FloatingLabelBehavior.never,
suffixIcon: IconButton(
onPressed: () {
Provider.of<LoginProvider>(context, listen: false)
.toggleObs();
},
icon: Provider.of<LoginProvider>(context,
listen: false)
.switchObsIcon,
),
labelText: 'Password',
errorStyle: TextStyle(color: AppColors.red),
hintStyle: TextStyle(
color: Color(0xff919AAA),
),
),
),
//passwordTextFormField(),
SizedBox(height: _height! / 30.0),
///password visibility handle by provider state management
TextFormField(
controller: confirmPasswordController,
validator: (value) {
if (value!.isEmpty) {
return "Please Enter Password!";
} else if (value.length < 6) {
return "Please Enter more than 6 digit .";
} else {
return null;
}
},
obscureText:
Provider.of<LoginProvider>(context, listen: false)
.isConfirmPassword,
keyboardType: TextInputType.emailAddress,
autofillHints: [AutofillHints.email],
cursorColor: AppColors.black,
style: TextStyle(
color: Color(0xff919AAA),
),
decoration: InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(25.0),
borderSide: BorderSide(
color: AppColors.textFieldColor,
),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(25.0),
borderSide: BorderSide(
color: AppColors.textFieldColor,
),
),
errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(25.0),
borderSide: BorderSide(
color: AppColors.red,
),
),
focusedErrorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(25.0),
borderSide: BorderSide(
color: AppColors.red,
),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(25.0),
borderSide: BorderSide(
color: AppColors.textFieldColor,
),
),
floatingLabelBehavior: FloatingLabelBehavior.never,
suffixIcon: IconButton(
onPressed: () {
Provider.of<LoginProvider>(context, listen: false)
.toggleObsData();
},
icon: Provider.of<LoginProvider>(context,
listen: false)
.switchObsIcons,
),
labelText: 'Confirm Password',
errorStyle: TextStyle(color: AppColors.red),
hintStyle: TextStyle(
color: Color(0xff919AAA),
),
),
),
],
),
),
),
SizedBox(height: _height! / 28),
SizedBox(height: _height! / 22),
submitButton(),
SizedBox(height: _height! / 35),
],
),
),
),
);}
),
),
);
}
///app-text Widget is used for app logo and icon in top side
Widget appText() {
return Container(
width: _width! * 0.90,
child: Column(
children: <Widget>[
Image.asset(
"assets/traveling-text-icon.png",
height: 60,
),
SizedBox(
height: 5,
),
],
),
);
}
///for validation we used a submit button
Widget submitButton() {
return Card(
elevation: 20.0,
shadowColor: Colors.blue[100],
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(20.0))),
child: Container(
height: 60,
width: _width! * .85,
decoration: BoxDecoration(
// boxShadow: [BoxShadow(color: AppColors.grey, blurRadius: 20.0)],
borderRadius: BorderRadius.circular(20.0),
gradient: LinearGradient(colors: [
AppColors.blue,
Colors.blue.shade900,
])),
child: MaterialButton(
onPressed: () {
if(passwordController.text==confirmPasswordController.text){
Navigator.pushReplacement(context,
MaterialPageRoute(builder: (context) => EmployeeBottomNavBar()));}
else{
print("password did not match");
}
},
child: Text(
AppStrings.submit,
style: TextStyle(
color: Colors.white, fontSize: 14, fontWeight: FontWeight.bold),
),
),
),
);
}
}
////provider class
import 'package:flutter/material.dart';
import 'package:traveling/helpers/AppColors.dart';
class LoginProvider extends ChangeNotifier {
bool _isTrue = true;
bool _isConfirmPassword = true;
bool get isTrue => _isTrue;
bool get isConfirmPassword => _isConfirmPassword;
get switchObsIcons {
return _isConfirmPassword ? Icon(Icons.visibility_off,color: AppColors.textFieldTextColor,) : Icon(Icons.visibility,color: AppColors.textFieldTextColor,);
}
get switchObsIcon {
return _isTrue ? Icon(Icons.visibility_off,color: AppColors.textFieldTextColor,) : Icon(Icons.visibility,color: AppColors.textFieldTextColor,);
}
void toggleObsData() {
_isConfirmPassword = !_isConfirmPassword;
notifyListeners();
}
void toggleObs() {
_isTrue = !_isTrue;
notifyListeners();
}
}