There were similar questions but their circumstances and solutions did not apply to my situation. All of my other inputs in the form work fine, but I've been banging my head against the wall for two weeks trying to figure this out.
Excuse the hacky code, we're migrating auth services and I had to find a way to handle multiple structures for the same data and detect which login method was used, but that's a tangent.
Anyway, here's my code. I'm relatively new at Flutter development so please tell me if I did something dumb.
import 'package:clash_of_the_pencils/widgets/body_text.dart';
import 'package:clash_of_the_pencils/widgets/box_container.dart';
import 'package:clash_of_the_pencils/widgets/general_button.dart';
import 'package:clash_of_the_pencils/widgets/heading_text.dart';
import 'package:clash_of_the_pencils/widgets/input_field.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:clash_of_the_pencils/models/auth_model.dart';
import 'package:go_router/go_router.dart';
import 'package:provider/provider.dart';
class RegistrationForm extends StatefulWidget {
const RegistrationForm({super.key});
@override
State<RegistrationForm> createState() => RegistrationFormState();
}
class RegistrationFormState extends State<RegistrationForm> {
String errorMessage = "";
String successMessage = "";
bool _pwObscure = true;
String firstName = "";
String lastName = "";
String codename = "";
String email = "";
String _password = "";
String codenameStr = "https://app.xxxxxxxxxxxxxxx.com/codename";
String dob = "";
@override
Widget build(BuildContext context) {
final user = context.watch<AuthModel>().user;
return MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => AuthModel()),
],
child: Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 20),
child: Center(
child: SingleChildScrollView(
child: Form(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
//* Top Heading and test
TextHeadings(
title: user['name'] != null
? "Just a few more details"
: "Registration",
textSize: 45,
),
const SizedBox(height: 10),
//* Box with the form
CustomBoxContainer(
boxContent: Center(
child: Column(children: [
//* Form Description
BodyText(
title: user['name'] != null
? "Complete the form below to finish registration"
: "Complete the form to create an account",
textSize: 18,
textColor: Colors.white,
textAlign: TextAlign.center,
fontWeight: FontWeight.bold,
),
const SizedBox(height: 25),
//* Error message
Container(
child: errorMessage != ""
? (Column(
children: [
CustomBoxContainer(
backgroundColor: const Color(0xffef5f5f),
borderColor: const Color(0xffef2828),
boxContent: BodyText(
title: errorMessage,
textAlign: TextAlign.center,
fontWeight: FontWeight.bold,
textColor: Colors.white,
),
),
const SizedBox(height: 25),
],
))
: null,
),
//* Success message
Container(
child: successMessage != ""
? (Column(
children: [
CustomBoxContainer(
backgroundColor: const Color(0xff79b441),
borderColor: const Color(0xff17974e),
boxContent: BodyText(
title: successMessage,
textAlign: TextAlign.center,
fontWeight: FontWeight.bold,
textColor: Colors.white,
),
),
const SizedBox(height: 25),
],
))
: null,
),
//* Codename Field
InputField(
child: TextFormField(
initialValue:
user[codenameStr] ?? user['nickname'] ?? codename,
decoration: const InputDecoration(
border: InputBorder.none,
labelText: "Codename",
hintText: "Choose a cool codename",
),
onChanged: (value) => setState(() {
codename = value;
}),
)),
const SizedBox(height: 10),
//* First Name Field
user['given_name'] == null
? InputField(
child: TextFormField(
decoration: const InputDecoration(
border: InputBorder.none,
hintText: "What's your first name?",
labelText: "First Name",
),
onChanged: (value) => {
setState(() {
firstName = value;
}),
},
initialValue: firstName.isNotEmpty
? firstName
: user['given_name'] ?? "",
),
)
: const SizedBox(
height: 0,
),
const SizedBox(height: 10),
//* Last Name Field
user['family_name'] == null
? InputField(
child: TextFormField(
decoration: const InputDecoration(
border: InputBorder.none,
hintText: "What's your last name?",
labelText: "Last Name",
),
onChanged: (value) => {
setState(() {
lastName = value;
}),
},
initialValue: lastName.isNotEmpty
? lastName
: user['family_name'] ?? ''))
: const SizedBox(height: 0),
SizedBox(height: user['family_name'] == null ? 10 : 0),
//* Email Field
user['email'] == null
? InputField(
child: TextFormField(
decoration: const InputDecoration(
border: InputBorder.none,
hintText: "[email protected]",
labelText: "Email",
),
initialValue: email.isNotEmpty
? email
: user['email'] ?? '',
))
: const SizedBox(height: 0),
SizedBox(height: user['email'] == null ? 10 : 0),
//* DOB Field
InputField(
child: TextFormField(
readOnly: true,
decoration: InputDecoration(
border: InputBorder.none,
labelText: 'Date of Birth',
suffixIcon: IconButton(
icon: const Icon(Icons.edit),
onPressed: () => showDatePicker(
initialDatePickerMode: DatePickerMode.year,
context: context,
initialDate: DateTime.now().subtract(
const Duration(days: 365 * 13)),
firstDate: DateTime(1900),
lastDate: DateTime.now().subtract(
const Duration(days: 365 * 13)))
.then(
(value) => {
setState(() {
dob =
'${value!.month.toString()}/${value.day.toString()}/${value.year.toString()}';
})
},
),
),
),
initialValue: dob,
)),
const SizedBox(height: 10),
// Password field
InputField(
child: TextFormField(
decoration: InputDecoration(
border: InputBorder.none,
labelText: 'Password',
suffixIcon: IconButton(
icon: Icon(_pwObscure
? Icons.visibility_off
: Icons.visibility),
onPressed: () {
setState(() {
_pwObscure = !_pwObscure;
});
},
)),
initialValue: _password.isNotEmpty ? _password : "",
obscureText: _pwObscure,
enableSuggestions: false,
onChanged: (value) => {
setState(() => {
if (!_pwObscure) _pwObscure = true,
_password = value,
}),
setState(() {
_pwObscure = true;
})
},
),
),
const SizedBox(height: 15),
//* Submit BTN
GeneralButton(
onPressed: () async {
// ignore: todo
// TODO: Write validation functions
Map<String, dynamic> userMetaData = {
'codename': codename.isNotEmpty
? codename
: user['nickname'],
'password': _password.isNotEmpty
? _password
: user['password'],
'dob': dob,
};
context
.read<AuthModel>()
.updateAuth0User({"user_metadata": userMetaData});
if (kDebugMode) {
print("***** Form Values Submitted");
}
},
buttonText: "Register",
),
const SizedBox(height: 15),
//* Separator
user['name'] == null
? const BodyText(
title: "- OR -",
textColor: Colors.white,
)
: const SizedBox(height: 0),
SizedBox(height: user['name'] == null ? 15 : 0),
//* Auth0 button
user['name'] == null
? GeneralButton(
onPressed: () {
Provider.of<AuthModel>(context, listen: false)
.login(true);
},
buttonText: "Register using auth0",
bgColor: Colors.white,
textColor: const Color(0xffFF7F34),
borderColor: const Color(0xffFF7F34),
)
: const SizedBox(height: 0),
]))),
user['name'] == null
? const SizedBox(height: 15)
: const SizedBox(height: 0),
//* Text for registering
user['name'] == null
? Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const BodyText(
title: "Already a member? ",
fontWeight: FontWeight.bold,
textColor: Colors.white,
textSize: 18,
),
GestureDetector(
onTap: () {
context.push('/login');
},
child: const BodyText(
title: "SIGN IN!",
fontWeight: FontWeight.bold,
textColor: Color(0xffFF7F34),
textSize: 18),
)
],
)
: const SizedBox(height: 0),
])),
),
),
));
}
@override
void dispose() {
super.dispose();
}
}
I picked a date from the DatePicker. I was expecting the UI to show the date that I picked. It did not. My formvalues updated but the new value doesn't show as it does with all of the other inputs.
CodePudding user response:
You have to control with TextEditingController
to setState
.
Instead of using initalValue
to setState, you need to use controller
.
TextFormField(
readOnly: true,
decoration: InputDecoration(
border: InputBorder.none,
labelText: 'Date of Birth',
suffixIcon: IconButton(
icon: const Icon(Icons.edit),
onPressed: () => showDatePicker(
initialDatePickerMode: DatePickerMode.year,
context: context,
initialDate:
DateTime.now().subtract(const Duration(days: 365 * 13)),
firstDate: DateTime(1900),
lastDate:
DateTime.now().subtract(const Duration(days: 365 * 13)))
.then(
(value) => {
setState(() {
dob =
'${value!.month.toString()}/${value.day.toString()}/${value.year.toString()}';
})
},
),
),
),
controller: TextEditingController(text: dob), //here is answer
),