Reputation: 123
I am developing an Expenses Management App in flutter, Here I am trying to create a DateTimePicker using showDatePicker(). therefore Inside my presentDateTimePicker() function i am calling showDatePicker() method.
and I am creating a variable for selectedDate where I am not initializing it to a current value since it will change based on the user input.
Inside my setState()
method I use _selectedDate = pickedDate
.
Still, it shows an error saying "non-nullable instance field"
My widget
//flutter imports
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:intl/intl.dart';
class NewTransaction extends StatefulWidget {
final Function addTx;
NewTransaction(this.addTx);
@override
_NewTransactionState createState() => _NewTransactionState();
}
class _NewTransactionState extends State<NewTransaction> {
final _titleController = TextEditingController();
final _amountController = TextEditingController();
final _brandNameControlller = TextEditingController();
DateTime _selectedDate;
void _submitData() {
final enteredTitle = _titleController.text;
final enteredAmount = double.parse(_amountController.text);
final enteredBrandName = _brandNameControlller.text;
if (enteredTitle.isEmpty || enteredAmount <= 0) {
return;
}
widget.addTx(
enteredTitle,
enteredAmount,
enteredBrandName,
);
Navigator.of(context).pop();
}
void _presentDateTimePicker() {
showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime(2019),
lastDate: DateTime.now(),
).then((pickedDate) {
if (pickedDate == null) {
return;
}
setState(() {
_selectedDate = pickedDate;
});
});
}
@override
Widget build(BuildContext context) {
return Card(
elevation: 5,
child: Container(
padding: EdgeInsets.all(10),
child: Column(
children: <Widget>[
TextField(
autocorrect: true,
decoration: InputDecoration(labelText: 'Title'),
controller: _titleController,
onSubmitted: (_) => _submitData,
//onChanged: (val) {
//titleInput = val;
//},
),
TextField(
autocorrect: true,
decoration: InputDecoration(labelText: 'Amount'),
controller: _amountController,
keyboardType: TextInputType.number,
onSubmitted: (_) => _submitData,
//onChanged: (val) => amountInput = val,
),
TextField(
autocorrect: true,
decoration: InputDecoration(labelText: 'Brand Name'),
controller: _brandNameControlller,
onSubmitted: (_) => _submitData,
//onChanged: (val) => brandInput = val,
),
Container(
height: 70,
child: Row(
children: <Widget>[
Text(_selectedDate == null
? 'No Date Chosen'
: 'Picked Date: ${DateFormat.yMd().format(_selectedDate)}'),
FlatButton(
onPressed: _presentDateTimePicker,
child: Text(
'Chose Date',
style: TextStyle(fontWeight: FontWeight.bold),
),
textColor: Theme.of(context).primaryColor,
),
],
),
),
RaisedButton(
onPressed: _submitData,
child: Text('Add Transaction'),
color: Theme.of(context).primaryColor,
textColor: Theme.of(context).textTheme.button!.color,
),
],
),
),
);
}
}
Upvotes: 2
Views: 2159
Reputation: 51
step1 : Put a question mark '?' after DateTime data type such as DateTime? _selectedDate;
Adding a question mark indicates to Dart that the variable can be null. I expect that initially the _selectedDate is not set, so Dart is giving an error warning due to null-safety. By putting a question mark in the type, you are saying you expect that the variable can be null (which is why it fixes the error).
step2 : whenever you would use it just check for null first by adding a null check (!)
After fixing errors your code is now :
//flutter imports
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:intl/intl.dart';
class NewTransaction extends StatefulWidget {
final Function addTx;
NewTransaction(this.addTx);
@override
_NewTransactionState createState() => _NewTransactionState();
}
class _NewTransactionState extends State<NewTransaction> {
final _titleController = TextEditingController();
final _amountController = TextEditingController();
final _brandNameControlller = TextEditingController();
DateTime? _selectedDate;
void _submitData() {
final enteredTitle = _titleController.text;
final enteredAmount = double.parse(_amountController.text);
final enteredBrandName = _brandNameControlller.text;
if (enteredTitle.isEmpty || enteredAmount <= 0) {
return;
}
widget.addTx(
enteredTitle,
enteredAmount,
enteredBrandName,
);
Navigator.of(context).pop();
}
void _presentDateTimePicker() {
showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime(2019),
lastDate: DateTime.now(),
).then((pickedDate) {
if (pickedDate == null) {
return;
}
setState(() {
_selectedDate = pickedDate;
});
});
}
@override
Widget build(BuildContext context) {
return Card(
elevation: 5,
child: Container(
padding: EdgeInsets.all(10),
child: Column(
children: <Widget>[
TextField(
autocorrect: true,
decoration: InputDecoration(labelText: 'Title'),
controller: _titleController,
onSubmitted: (_) => _submitData,
//onChanged: (val) {
//titleInput = val;
//},
),
TextField(
autocorrect: true,
decoration: InputDecoration(labelText: 'Amount'),
controller: _amountController,
keyboardType: TextInputType.number,
onSubmitted: (_) => _submitData,
//onChanged: (val) => amountInput = val,
),
TextField(
autocorrect: true,
decoration: InputDecoration(labelText: 'Brand Name'),
controller: _brandNameControlller,
onSubmitted: (_) => _submitData,
//onChanged: (val) => brandInput = val,
),
Container(
height: 70,
child: Row(
children: <Widget>[
Text(_selectedDate == null
? 'No Date Chosen'
: 'Picked Date: ${DateFormat.yMd().format(_selectedDate!)}'),
FlatButton(
onPressed: _presentDateTimePicker,
child: Text(
'Chose Date',
style: TextStyle(fontWeight: FontWeight.bold),
),
textColor: Theme.of(context).primaryColor,
),
],
),
),
RaisedButton(
onPressed: _submitData,
child: Text('Add Transaction'),
color: Theme.of(context).primaryColor,
textColor: Theme.of(context).textTheme.button!.color,
),
],
),
),
);
}
}
Upvotes: 0
Reputation: 27
There is a work around in this situation
initialize the date with
DateTime _selectedDate = DateTime.parse('0000-00-00');
and later on in text widget instead of
Text(_selectedDate == null
? 'No Date Chosen'
: 'Picked Date: ${DateFormat.yMd().format(_selectedDate!)}'),
use
Text(_selectedDate == DateTime.parse('0000-00-00')
? 'No Date Chosen'
: 'Picked Date: ${DateFormat.yMd().format(_selectedDate!)}'),
Upvotes: 1
Reputation: 1319
If you will change the value in the setState method, you can initialize the variable with
DateTime _selectedDate = DateTime.now();
and format it to the format you show the user, this would get rid of the error and if you are going to change it each time the user selects a date, seeing the current date as a starting value gives the user a starting point as a reference.
Upvotes: 0
Reputation: 5733
If the value is nullable just mark the variable as such DateTime? _selectedDate;
And whenever you would use it just check for null first:
Text(_selectedDate == null
? 'No Date Chosen'
: 'Picked Date: ${DateFormat.yMd().format(_selectedDate!)}'),
// Here you do know that the value can't be null so you assert to the compiler that
Check out the official docs on null safety they are extremely high quality and instructive.
There you can read about when to use nullable ?
non nullable or late
variables.
Upvotes: 3