TimeToCode
TimeToCode

Reputation: 1838

Flutter: A non-null String must be provided to a Text widget. Failed assertion: line 378 pos 10: 'data != null'

I getting data from API and adding it to data table, it's working fine, when i select month from dropdown, my data table get modify according to selected month from drop down, but initially it print this error.

enter image description here

and its change to this when i select month from dropdown

enter image description here

here is code



class MyAttendance extends StatefulWidget {
  

  @override
  _MyAttendanceState createState() => _MyAttendanceState();
}

class _MyAttendanceState extends State<MyAttendance> {
  //List<History> _historyList;
  List<History> historyList=[];
  String _selectedLeave;
  int monthIndex;
  int month;
  var monthsList=<String>[
      'January',
      'Febuary',
      'March',
      'April',
      'May',
      'June',
      'July',
      'Augest',
      'September',
      'October',
      'November',
      'December'
  ];
  String getdate="";
    void _getDate() {
    final String formattedDateTime =
        DateFormat('MM').format(DateTime.now()).toString();
    setState(() {
      getdate = formattedDateTime;
     print("date  "+getdate);
    });
  }
  _userDetails() async{
    SharedPreferences myPrefs=await SharedPreferences.getInstance();
    setState(() {
          getname=myPrefs.getString('name');         
        }); 
   }
   void initState() {
      _userDetails();
      _getDate();
      _getRecord();
    }
  Future<List<History>> _getRecord() async{
   Dio dio=new Dio();
   var data={
     'username':getname,
     'month':month
   };
   return dio
    .post(localhostUrlAttendanceHistory,data: json.encode(data))
      .then((onResponse) async {
        var jsonData=onResponse.data['data'];
        //List<History> historyList = [];
        for (var h in jsonData) {
          History history = History(
            h["Date"], 
            h["TimeIn"], 
            h["TimeOut"],
          );
          historyList.add(history);
        }
        return historyList;
      })
      .catchError((onerror){
        print(onerror.toString());
       
    });
  }
  Widget attendanceHistory(List<History> 

    historyList)=>  
        DataTable(columns: <DataColumn>[
        DataColumn(label: Text("Date"),),
        DataColumn(label: Text("Time in" ),),
        DataColumn(label: Text("Time out")
    )],
    rows: 
    historyList
      ?.map((element)=>DataRow(
      cells: <DataCell>[
      DataCell(Text(element?.date)),
      DataCell(Text(element?.timeIn)),
      DataCell(Text(element?.timeOut)),
    ]) )?.toList());
  
  
  TextEditingController fromDate=new TextEditingController();
  TextEditingController toDate=new TextEditingController();
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: new MyAppBar(title: Text("My Attendance"),onpressed: (){
       Navigator.push(context, MaterialPageRoute(builder: (context)=>Profile()));
   }),
    
    drawer:Emp_DrawerCode(),
   
    body:Stack(children: <Widget>[
       Container(
        padding: EdgeInsets.fromLTRB(25, 15, 0, 0),
        child: Text("Attendance history",style: TextStyle(fontSize: 30,color: Colors.blue[900],fontWeight: FontWeight.bold),),
        ),
        Container(
        padding: EdgeInsets.fromLTRB(45, 80, 10, 0),
        child:
        DropdownButton<String>(
        value: _selectedLeave==null?null:monthsList[monthIndex],    
        items: 
          monthsList   
          .map<DropdownMenuItem<String>>((String value) {
            return DropdownMenuItem<String>(
              value: value,
              child: Text(value)
            );
          }).toList(),
          hint:Text(
            "Please choose a month",
          ),
          onChanged: (String value) {
            setState(() {
              _selectedLeave=value;
              monthIndex = monthsList.indexOf(value);
              month=monthIndex+1;
              print(month);
              print(_selectedLeave);
            });
          },
        ),
      ),

    Container(
    padding: EdgeInsets.fromLTRB(15, 150, 0, 0),
    child:SingleChildScrollView(
      scrollDirection: Axis.vertical,
    
    child: FutureBuilder(
    future: _getRecord(),
    
    builder: (BuildContext context, AsyncSnapshot<List<History>> snapshot) {
      // Check if the data has been received.
      if (snapshot.hasData) {
        // Return the widget and provide the received data.
        return attendanceHistory(snapshot.data);
      }
      return Center(child: CircularProgressIndicator(),);
      // print("data");
      // print(snapshot.data);
      // Text("No data is shown");
      //return attendanceHistory(snapshot.data);
     
    }
  ),
),)

   

    ]));
  }
}

class History {
  
  final String date;
  final String timeIn;
  final String timeOut;
  

  History(this.date, this.timeIn, this.timeOut);

}

Error

════════ Exception caught by widgets library ═══════════════════════════════════
A non-null String must be provided to a Text widget.
'package:flutter/src/widgets/text.dart':
Failed assertion: line 378 pos 10: 'data != null'

The relevant error-causing widget was
FutureBuilder<List<History>>
lib\My_Attendance\MyAttendance.dart:171

Update: After few seconds of red screen error, it display this, and i have not select month from dropdown too.

enter image description here

and it sends this error now

════════ Exception caught by widgets library ═══════════════════════════════════
The method 'map' was called on null.
Receiver: null
Tried calling: map<DataRow>(Closure: (History) => DataRow)
The relevant error-causing widget was
FutureBuilder<List<History>>

Update

Error: enter image description here

Update:

  builder: (BuildContext context, AsyncSnapshot<List<History>> snapshot) {
      // Check if the data has been received.
      if(snapshot.connectionState==ConnectionState.done){
        if (snapshot.hasData) {
          return Center(
            child: Text('${snapshot.error} occured',
        style: TextStyle(fontSize: 18)),
          );
        }
        else if(snapshot.hasData){
         
            return attendanceHistory(snapshot.data);
          }
        
        // Return the widget and provide the received data.
          //return Center(child: CircularProgressIndicator(),);
      }
      //return attendanceHistory(snapshot.data);
      return Center(child: CircularProgressIndicator(),);
      // print("data");
      // print(snapshot.data);
      // Text("No data is shown");
      
     
    }
  ),

kindly please help how i can fix it?

Upvotes: 1

Views: 489

Answers (2)

Raju Gupta
Raju Gupta

Reputation: 802

A better practice is to use loader while fetching the data from API. Since future builder has a property to check whether there is response from API or not. TO check this simply use

`FutureBuilder(
future: _getRecord(),

builder: (BuildContext context, 

AsyncSnapshot<List<History>> snapshot) {
  // Below line will check whether future has data or not
if (snapshot.connectionState == ConnectionState.done) {
  // If we got an error
  if (snapshot.hasError) {
    return Center(
      child: Text(
        '${snapshot.error} occured',
        style: TextStyle(fontSize: 18),
      ),
    );
      
    // if we got our data
  } else if (snapshot.hasData) {**strong text**
  if (snapshot.hasData) {
    
    return attendanceHistory(snapshot.data);
  }
 return Center(child: CircularProgressIndicator(),);
}`

Or else you can use null aware operator to handle the null value as below.

 Widget attendanceHistory(List<History> 

 historyList)=>  
 DataTable(columns: <DataColumn>[
DataColumn(label: Text("Date"),),
DataColumn(label: Text("Time in" ),),
DataColumn(label: Text("Time out")
)],
rows: 
historyList
?.map((element)=>DataRow(
cells: <DataCell>[
DataCell(Text(element?.date)),
DataCell(Text(element?.timeIn)),
DataCell(Text(element?.timeOut)),

]) )?.toList());

Upvotes: 1

TheAlphamerc
TheAlphamerc

Reputation: 916

This error generate when you pass a null value to Text widget. So to avoid this either you can put a null check condition before displaying text or you can pass a default value to the Text widget.

 Widget attendanceHistory(List<History> historyList)=>  
  DataTable(columns: <DataColumn>[
    DataColumn(label: Text("Date"),),
    DataColumn(label: Text("Time in" ),),
    DataColumn(label: Text("Time out")
    )],
  rows: 
  historyList
  .map((element)=>DataRow(
    cells: <DataCell>[
    DataCell(Text(element.date ?? "N/A")),
    DataCell(Text(element.timeIn ?? "N/A")),
    DataCell(Text(element.timeOut ?? "N/A")),
  ])
  ).toList());

Display CircularProgressIndicator while fetching the records.

Container(
    padding: EdgeInsets.fromLTRB(15, 150, 0, 0),
    child:SingleChildScrollView(
      scrollDirection: Axis.vertical,
    
    child: FutureBuilder(   //This is line 171
    future: _getRecord(),
    
    builder: (BuildContext context, AsyncSnapshot<List<History>> snapshot) {
      // Check if the data has been received.
      if (snapshot.hasData) {
        // Return the widget and provide the received data.
        return attendanceHistory(snapshot.data);
      }
     return Center(child: CircularProgressIndicator(),);
    }
  ),

Upvotes: 1

Related Questions