hamjeth Misree
hamjeth Misree

Reputation: 123

Non-nullable instance field '_selectedDate' must be initialized

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

Answers (4)

Syeed Talha
Syeed Talha

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

Hassan Raza
Hassan Raza

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

Jaime Ortiz
Jaime Ortiz

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

croxx5f
croxx5f

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

Related Questions