Flutter Qs : The getter 'length' was called on null - flutter

So I already make Condition where if the data called is null so it will Show No Data but it still have an Error.
Here's the code
Center(
child: ListView.builder(
itemCount: data.length,
itemBuilder: (BuildContext context, int index) {
if (data[index] == null) {
return Container(
child: Center(
child: Text(
"No News"
)
)
);
} else {
return GestureDetector(
onTap: () {
Navigator.push(context, MaterialPageRoute(
builder: (context) =>
DetailNewsScreen(
data: data[index],
)));
},
child: Card(
child: Row(
but it still show error

You have to check if your data variable is null, otherwise you cannot call data.length as the itemCount
You're currently checking if data[index] is not null but not data itself
You could try :
Center(
child: ListView.builder(
itemCount: data == null ? 0 : data.length,
itemBuilder: (BuildContext context, int index) {
if (data[index] == null) {
return Container(child: Center(child: Text("No News")));
} else {
// return whatever widget you want
}
}),
),

the data is null, not data[someIndex]
itemCount: data.length,
You didnt cover the case where data==null. The most straightforward way of fixing it, is to assing empty array.
if(data==null) data=[]; somewhere prior building the view.

Related

Why is there an error with snapshot.data.length?

I am trying to parse data from an API. For that, I am using FutureBuilder to list all the parsed data in a ListView.
I've performed a check for nullity of snapshot.data but I keep on getting this error in the segment snapshot.data.length, it says, The property 'length' can't be unconditionally accessed because the receiver can be 'null'. Try making the access conditional (using '?.') or adding a null check to the target ('!').
I've a similar error in the snapshot.data[i] section, which says The method '[]' can't be unconditionally invoked because the receiver can be 'null'. Try making the call conditional (using '?.') or adding a null check to the target ('!').
Here is my code's section of the same:
body: Container(
child: FutureBuilder(
future: getData('hello'),
builder: (context, snapshot) {
if (snapshot.data == null) {
return Container(
child: Text("Loading"),
);
}else{
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, i) {
return ListTile(
title: snapshot.data[i].partOfSpeech,
);
});
}
},
),
),
Here's getData(String s):
Future<List> getData(String s) async {
var response = await http
.get(Uri.https('api.dictionaryapi.dev', 'api/v2/entries/en_US/' + s));
var jsonData = jsonDecode(response.body)[0];
List<Data> data = [];
for (var x in jsonData["meanings"]) {
String definition = x["definitions"][0]["definition"];
Data d = Data(x["partOfSpeech"], definition);
data.add(d);
}
return data;
}
if u are using a new version of flutter (2.2.0 or above). first try adding a null check to the target ('!'). because of the null safety feature.
body: Container(
child: FutureBuilder(
future: getData('hello'),
builder: (context, snapshot) {
if (snapshot.data == null) {
return Container(
child: Text("Loading"),
);
}else{
return ListView.builder(
itemCount: snapshot.data!.length,
itemBuilder: (context, i) {
return ListTile(
title: snapshot.data[i].partOfSpeech,
);
});
}
},
),
),
then try specifying the FutureBuilder type to a List of Data type
body: Container(
child: FutureBuilder<List<Data>>(
future: getData('hello'),
builder: (context, snapshot) {
if (snapshot.data == null) {
return Container(
child: Text("Loading"),
);
}else{
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, i) {
return ListTile(
title: snapshot.data[i].partOfSpeech,
);
});
}
},
),
),
In continuation to this answer,
I found the solution to my problem. Apparently getData was not returning a List as intended. Instead, it was returning an Object.
Typecasting the Object to List solved the problem.
Here's the corrected code:
body: Container(
child: FutureBuilder(
future: getData('hello'),
builder: (context, snapshot) {
if (snapshot.data == null) {
return Container(
child: Text("Loading"),
);
}else{
//typecasting Object to List
var data = (snapshot.data as List<Data>).toList();
return ListView.builder(
itemCount: data.length,
itemBuilder: (context, i) {
return ListTile(
title: data[i].partOfSpeech,
);
});
}
},
),
),
Put 'AsyncSnapshot' before snapshot in the builder parameter.
builder: (context, AsyncSnapshot snapshot)
Since you are checking that snapshot.data is not null you can do the following to fix it.
body: Container(
child: FutureBuilder(
future: getData('hello'),
builder: (context, snapshot) {
if (snapshot.data == null) {
return Container(
child: Text("Loading"),
);
} else{
return ListView.builder(
itemCount: snapshot.data!.length,
itemBuilder: (context, i) {
return ListTile(
title: snapshot.data[i]!.partOfSpeech,
);
});
}
},
),
),
What you need to look at is the result of getData('hello')
Apparently, it does not return something that has a length property.

The getter 'documents' was called on null

I'm using flutter and firebase to make a to-do list. It keeps showing me this error even after I checked if my snap.data == null .But I am not sure why still doesn't work.
please help. I have checked similar problems like this but still didn't solve
sorry for my English
body: StreamBuilder(
stream: Firestore.instance.collection("MyTodos").snapshots(),
builder: (context, snapshots) {
return ListView.builder(
shrinkWrap: true,
itemCount: snapshots.data.documents.length,
itemBuilder: (context, index) {
DocumentSnapshot documentSnapshot =
snapshots.data.documents[index];
return Dismissible(
key: Key(index.toString()),
child: Card(
child: ListTile(
title: Text(documentSnapshot["todoTitle"]),
trailing: IconButton(
icon: Icon(Icons.delete),
onPressed: () {
setState(() {
todos.removeAt(index);
});
},
),
),
),
);
},
);
},
)
StreamBuilder has a default state before it gets any data at all, and you need to check for this state so you don't try to build using data that doesn't exist yet. You can do this by checking either snapshots.hasData or snapshots.data == null:
StreamBuilder(
...
builder: (context, snapshots) {
if (!snapshots.hasData) {
return CircularProgressIndicator();
}
else {
return ListView.builder(
...
);
}
},
),

flutter: randomize item count in list View

i implemented listView in flutter and it shows product count=5 , but i wanted these 5 items to be generated randomly , is there a way to do it? thanks in advance
ps: i tried code depending on answer below but it gives me error count!=null
Expanded(
child: SizedBox(
height: 210.0,
child: FutureBuilder(
future: httpService.getProducts(),
builder:
(BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.data == null) {
return Container(
child: Center(
child: Text('Loading...'),
),
);
} else if (snapshot.data.length == 0) {
return Container(
child: Center(
child: Center(
child: Text('No offers'),
),
),
);
} else {
var rndItems = snapshot.data.shuffle();
return ListView.separated(
separatorBuilder:
(BuildContext context, int index) {
return SizedBox(height: 3);
},
scrollDirection: Axis.horizontal,
shrinkWrap: true,
itemCount: rndItems ,
itemBuilder: (ctx, i) => (PdtItem(
title: snapshot.data[i].title,
imgUrl: snapshot.data[i].imgUrl,
price: snapshot.data[i].price,
pdt2: snapshot.data[i])),
);
If you want the items from snapshot.data to be listed in a random order then you may shuffle the data as follows :
....
snapshot.data.shuffle();
....
If you want to display random number of items everytime then
....
import 'dart:math';
....
var rng = new Random();
var rndItems = rng.nextInt(snapshot.data.length);
....
.....
scrollDirectionn: Axis.horizontal,
shrinkWrap: true,
itemCount: rndItems,
itemBuilderr: (ctx, i) => (PdtItem(
.....

Flutter ListView builder never completes

So im stuck on something that normally just works.
I have a firebase collection which contains a list of temmplates, i want to show these templates as a list view tile.
Stepping through the code reveals that the stream returns the items successfully , however when it reaches the itemCount property of the ListView it jumps out of the IF statement entirely and continues to display the loading indicator.
Debug console isnt showing any errors at all
StreamBuilder(
stream: firestoreDatabase.templatesStream(),
initialData: new List<AppTemplate>(),
builder: (context, snapshot) {
if (snapshot.data != null) {
List<AppTemplate> templates = snapshot.data;
ListView.builder(
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemBuilder: (context, index) {
return ListTile(
title: Text(templates[index].title),
subtitle: Text(
templates[index].description == null ||
templates[index].description == ""
? "N/A"
: templates[index].description),
leading: Icon(Icons.collections),
trailing: GestureDetector(
onTap: () => {},
child: Icon(Icons.delete),
),
);
},
itemCount: templates.length,
);
} else if (snapshot.hasError) {
return Center(child: Text('Error'));
}
return Center(
child: CircularProgressIndicator(),
);
},
),

Flutter: When the snapshot is empty the widget disappears

I am trying to build a search list, the list is working fine but if the result is empty i need to show no data. I tried the following code but the widget holds for a second and then disappear
FutureBuilder(
future: getSearchedProducts(widget.searchString),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (!snapshot.hasData) {
return Center(
child: Container(
child: Text('No Data Found.'),
),
);
} else {
return ListView.builder(
shrinkWrap: true,
itemCount: searchResult.length,
scrollDirection: Axis.vertical,
itemBuilder: (context, index) {
return Card(
child: ListTile(
leading: Image.network(searchResult[index].proThumbnail),
title: Text(searchResult[index].proName),
onTap: () {
print(searchResult[index].proName);
Navigator.push(context, MaterialPageRoute(builder: (context) {
return ProductPage(prodid: searchResult[index].proId);
}));
},
),
);
});
}
})
Can anyone help me with this.
Thank you in advance.
I just write the code as below and it works.
FutureBuilder(
future: getSearchedProducts(widget.searchString),
builder: (BuildContext context, AsyncSnapshot snapshot) {
print('length of list ${searchResult.length}');
if (searchResult.length==0) {
return Center(
child: Text('No data'),
);
}
else if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(),
);
}
else {
return ListView.builder(
shrinkWrap: true,
itemCount: searchResult.length,
scrollDirection: Axis.vertical,
itemBuilder: (context, index) {
return Card(
child: ListTile(
leading: Image.network(searchResult[index].proThumbnail),
title: Text(searchResult[index].proName),
onTap: () {
print(searchResult[index].proName);
Navigator.push(context, MaterialPageRoute(builder: (context) {
return ProductPage(prodid: searchResult[index].proId);
}));
},
),
);
});
}
}),
In your Code in Else part before - return ListView.builder- add the following code.
...
else {
if (searchResult.length == 0)
{
return Center(child: const Text('No Date'));
}
return ListView.builder .....