Bad state: field does not exist within the DocumentSnapshotPlatform | flutter - flutter

How to fix this,
error says,
════════ Exception caught by widgets library ═══════════════════════════════════
The following StateError was thrown building:
Bad state: field does not exist within the DocumentSnapshotPlatform
Another problem is when the user searches for something, the app should show the username without considering capital, simple words
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'package:insta/utils/colors.dart';
class SearchScreen extends StatefulWidget {
const SearchScreen({super.key});
#override
State<SearchScreen> createState() => _SearchScreenState();
}
class _SearchScreenState extends State<SearchScreen> {
final TextEditingController searchCon = TextEditingController();
bool isShowUsers = false;
#override
void dispose() {
searchCon.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: mobileBackgroundColor,
title: TextFormField(
controller: searchCon,
decoration: const InputDecoration(
labelText: "Search for a user",
),
onChanged: (value) {
setState(() {
isShowUsers = true;
});
},
// onFieldSubmitted: (String _) {
// setState(() {
// isShowUsers = true;
// });
// },
),
),
body: isShowUsers
? FutureBuilder(
future: FirebaseFirestore.instance
.collection('users')
.where(
'username',
isGreaterThanOrEqualTo: searchCon.text,
)
.get(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return const Center(
child: CircularProgressIndicator(),
);
}
return ListView.builder(
itemCount: (snapshot.data! as dynamic).docs.length,
itemBuilder: (context, index) {
return ListTile(
leading: CircleAvatar(
backgroundImage: NetworkImage(
(snapshot.data! as dynamic).docs[index]
['photoUrl']),
),
title: Text(
(snapshot.data! as dynamic).docs[index]['username']),
);
},
);
},
)
: FutureBuilder(
future: FirebaseFirestore.instance.collection('posts').get(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center(child: const CircularProgressIndicator());
}
return StaggeredGridView.countBuilder(
crossAxisCount: 3,
itemCount: (snapshot.data! as dynamic).docs.length,
itemBuilder: (context, index) => Image.network(
(snapshot.data! as dynamic).docs[index]['postUrl'],
fit: BoxFit.cover,
),
staggeredTileBuilder: (index) => StaggeredTile.count(
(index % 7 == 0) ? 2 : 1, (index % 7 == 0) ? 2 : 1),
mainAxisSpacing: 8.0,
crossAxisSpacing: 8.0,
);
},
),
);
}
}
`

Got this error while working with firebase its due to when you are trying to access the document doesn't exist or check the spelling, syntax when you access them

Related

The getter 'length' was called on null. Receiver: null Tried calling: length (Thanks to who helps me)

I am not an expert in flutter, I am still learning it but I cannot understand where I am wrong.
I thank anyone who wants to help me
I am not an expert in flutter, I am still learning it but I cannot understand where I am wrong.
I thank anyone who wants to help me
I am not an expert in flutter, I am still learning it but I cannot understand where I am wrong.
I thank anyone who wants to help me
import 'package:flutter/material.dart';
import 'package:todo_app/database_helper.dart';
import 'package:todo_app/screens/taskpage.dart';
import 'package:todo_app/widgets.dart';
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
DatabaseHelper _dbHelper = DatabaseHelper();
#override
Widget build(
BuildContext context,
) {
return Scaffold(
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.deepPurple,
child: Icon(Icons.add),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => TaskPage(),
),
);
},
),
body: SafeArea(
child: Container(
width: double.infinity,
padding: EdgeInsets.symmetric(horizontal: 24),
margin: EdgeInsets.only(bottom: 20),
color: Colors.grey[100],
child: Stack(children: [
Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
Container(
margin: EdgeInsets.only(bottom: 32),
child: Text(
'Logo',
style: TextStyle(fontSize: 22),
),
),
Expanded(
child: FutureBuilder(
future: _dbHelper.getTasks(),
builder: (context, AsyncSnapshot snapshot) {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
return TaskCardWidget(
title: snapshot.data[index].title,
desc: snapshot.data[index].description,
);
});
},
),
),
])
]),
),
),
);
}
}
// This is the database class instead
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
import 'package:todo_app/models/task.dart';
class DatabaseHelper {
Future<Database> database() async {
return openDatabase(
join(await getDatabasesPath(), 'todo_database.db'),
onCreate: (db, version) {
return db.execute(
"CREATE TABLE task(id INTEGER PRIMARY KEY, title TEXT, description TEXT)",
);
},
version: 1,
);
}
Future<void> insertTask(Task task) async {
Database _db = await database();
await _db.insert('task', task.toMap(),
conflictAlgorithm: ConflictAlgorithm.replace);
}
Future<List<Task>> getTasks() async {
final Database _db = await database();
final List<Map<String, dynamic>> taskMap = await _db.query('tasks');
return List.generate(
taskMap.length,
(index) => Task(
id: taskMap[index]['id'],
title: taskMap[index]['title'],
description: taskMap[index]['description'],
));
}
}
Initially when your Future isn't completed, you don't have the data from the AsyncSnapshot. Try adding the following checks in your FutureBuilder.
FutureBuilder(
future: _dbHelper.getTasks(),
builder: (context, AsyncSnapshot snapshot) {
if (snapshot.hasError) {
return Text('${snapshot.error}');
} else if (snapshot.hasData) {
return ListView.builder(...);
}
return Center(child: CircularProgressIndicator()); // Default loading
},
)

Flutter how to change the background color of a selected tile from a ListTile

I am trying to change the background of a selected tile from a ListTile.
I searched and found the following two posts, however non of them worked with my problem.
Post1
Post2
The better I got was with the help from #CopsOnRoad's answere.
With the following code, if I select multiple tiles, all remain select. How to select only one at the time and deselect the previous selected?
The tile index is limited by itemCount: is books.length.
List<Favorited> books;
// todo: this needs to be changed, has a hard coded value of 200
List<bool> _selected = List.generate(200, (i) => false); // Pre filled list
#override
Widget build(BuildContext context) {
final booksProvider = Provider.of<Model>(context);
return Container(
child: StreamBuilder(
stream: booksProvider.getUserFavList('103610812025'),
builder: (context, AsyncSnapshot<List<Favorited>> snapshot) {
if (snapshot.hasData) {
books= snapshot.data.toList();
return ListView.builder(
itemCount: books.length,
itemBuilder: (buildContext, index) {
return Container(
color: _selected[index] ? Colors.amber : Colors.transparent,
child: ListTile(
title: InkWell(
child: Text(snapshot.data[index].title),
onTap:() {
setState(() {
_selected[index] = !_selected[index];
});
}),
subtitle: Text(snapshot.data[index].name),
),
);
});
} else {
return Text('Fetching');
}
}),
);
Let a one variable to save selected tile index.
List<Favorited> books;
// todo: this needs to be changed, has a hard coded value of 200
List<bool> _selected = List.generate(200, (i) => false); // Pre filled list
int selectedIndex;
#override
Widget build(BuildContext context) {
final booksProvider = Provider.of<Model>(context);
return Container(
child: StreamBuilder(
stream: booksProvider.getUserFavList('103610812025'),
builder: (context, AsyncSnapshot<List<Favorited>> snapshot) {
if (snapshot.hasData) {
books= snapshot.data.toList();
return ListView.builder(
itemCount: books.length,
itemBuilder: (buildContext, index) {
return Container(
color: selectedIndex == index ? Colors.amber : Colors.transparent,
child: ListTile(
title: InkWell(
child: Text(snapshot.data[index].title),
onTap:() {
setState(() {
selectedIndex = index;
});
}),
subtitle: Text(snapshot.data[index].name),
),
);
});
} else {
return Text('Fetching');
}
}),
);

single document in same collection Firestore Flutter

I build a quiz app and i use firestore for the data, i need a code for this : when the user select answer 1 he goes to page A , but when he select answer 2 he goes to page B ... etc
This is where am i : all the answers go to the same page when i tap on it, i want for every answer has his own page
This is my code :
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
class question14 extends StatefulWidget {
#override
_question14State createState() => _question14State();
}
class _question14State extends State<question14> {
int selectedIndex
#override
Widget build(BuildContext context) {
return Scaffold(
body: StreamBuilder(
stream: Firestore.instance.collection('numberzz').snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) return const Text('Loading ...');
return ListView.builder(
scrollDirection: Axis.horizontal,
padding: EdgeInsets.fromLTRB(100.0, 0.0, 0.0, 0.0),
itemExtent: 200.0,
itemCount: snapshot.data.documents.length,
itemBuilder: (BuildContext context, int index) {
final DocumentSnapshot document =
snapshot.data.documents[index];
return Container(
padding: EdgeInsets.fromLTRB(0.0, 300.0, 0.0, 450.0),
child: ListTile(
contentPadding: selectedIndex == index
? EdgeInsets.all(0.0)
: EdgeInsets.all(25.0),
title: Image.network(
document['number'],
),
selected: selectedIndex == index,
onTap: () {
Firestore.instance.runTransaction((transaction) async {
DocumentSnapshot freshSnap =
await transaction.get(document.reference);
await transaction.update(freshSnap.reference, {
'vote': freshSnap['vote'] + 1,
});
});
Navigator.push(
context, MaterialPageRoute(
builder: (context) => new page()));
setState(() {
selectedIndex = index;
});
},
),
);
},
);
}));
}
}
thanks for your help !
You can check which index is selected before navigating. Kind of conditional navigation.
switch(selectedIndex){
case 0:
Navigator.of(context).push(.....(Page A));
break;
case 1:
.......
break;
I think you get the point.
But this code should come after
setState(() { selectedIndex = index };

what is missing here ? Flutter - single selection

i'm creating a quiz app and i want to make some questions with single selection answer,
this is what it looks like for now :
Full code :
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
class question14 extends StatefulWidget {
#override
_question14State createState() => _question14State();
}
class _question14State extends State<question14> {
final isSelected = [false, false, false];
#override
Widget build(BuildContext context) {
return Scaffold(
body: StreamBuilder(
stream: Firestore.instance
.collection('numberzz')
.snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) return const Text('Loading ...');
return ListView.builder(
scrollDirection: Axis.horizontal,
padding: EdgeInsets.fromLTRB(100.0, 0.0, 0.0, 0.0),
itemExtent: 200.0,
itemCount: snapshot.data.documents.length,
itemBuilder: (BuildContext context, int index) {
final DocumentSnapshot document =
snapshot.data.documents[index];
return
Container(
padding: EdgeInsets.fromLTRB(0.0, 300.0, 0.0, 450.0),
child: ListTile(
contentPadding: isSelected[index]
? EdgeInsets.all(0.0)
: EdgeInsets.all(25.0),
title: Image.network(
document['number'],
),
selected: !isSelected[index],
onTap: () {
Firestore.instance.runTransaction((transaction) async {
DocumentSnapshot freshSnap =
await transaction.get(document.reference);
await transaction.update(freshSnap.reference, {
'vote': freshSnap['vote'] + 1,
});
});
setState(() {
isSelected[index] = !isSelected[index];
});
},
),
);
},
);
);
}
}
thanks you so much for your help !
Instead of using list of booleans, you can just store the selected index.
I used selectedIndex to have the answer's selection which is selected by the user at last.
Updated code:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
class question14 extends StatefulWidget {
#override
_question14State createState() => _question14State();
}
class _question14State extends State<question14> {
int selectedIndex = 0;//for unselect, you can use null
#override
Widget build(BuildContext context) {
return Scaffold(
body: StreamBuilder(
stream: Firestore.instance.collection('numberzz').snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) return const Text('Loading ...');
return ListView.builder(
scrollDirection: Axis.horizontal,
padding: EdgeInsets.fromLTRB(100.0, 0.0, 0.0, 0.0),
itemExtent: 200.0,
itemCount: snapshot.data.documents.length,
itemBuilder: (BuildContext context, int index) {
final DocumentSnapshot document =
snapshot.data.documents[index];
return Container(
padding: EdgeInsets.fromLTRB(0.0, 300.0, 0.0, 450.0),
child: ListTile(
contentPadding: selectedIndex == index
? EdgeInsets.all(0.0)
: EdgeInsets.all(25.0),
title: Image.network(
document['number'],
),
selected: selectedIndex == index,
onTap: () {
Firestore.instance.runTransaction((transaction) async {
DocumentSnapshot freshSnap =
await transaction.get(document.reference);
await transaction.update(freshSnap.reference, {
'vote': freshSnap['vote'] + 1,
});
});
setState(() {
selectedIndex = index;
});
},
),
);
},
);
}));
}
}

Avoid StreamBuilder refreshing running SetState in Flutter

I have a page which displays 2 elements, both of them are different StreamBuilder but the second one depends on the first one.
To make it more clear I display this:
Firebase documents (list)
Firebase user
If we sign out both StreamBuilder disappear. That's fine, but my problem comes when I need to select a document from the list:
return ListTile(
leading: FlutterLogo(size: 40.0),
title: Text(set["title"]),
selected: _selected[index],
trailing: Badge(
badgeColor: Colors.grey,
shape: BadgeShape.circle,
toAnimate: true,
onTap: () => setState(() => _selected[index] = !_selected[index]),
);
Everytime I do the SetState() I refresh the first StreamBuilder (not sure why) and with this the second one.
This is the list widget:
Widget _mySetsLists(BuildContext context) {
List<bool> _selected = List.generate(20, (i) => false);
return StreamBuilder(
stream: FirebaseAuth.instance.onAuthStateChanged,
builder: (context, snapshot) {
FirebaseUser user = snapshot.data;
if (snapshot.hasData) {
return StreamBuilder(
stream: Firestore.instance
.collection('users')
.document(user.uid)
.collection('sets')
.snapshots(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
return new ListView.builder(
shrinkWrap: true,
itemCount: snapshot.data.documents.length,
itemBuilder: (context, index) {
DocumentSnapshot set = snapshot.data.documents[index];
return ListTile(
leading: FlutterLogo(size: 40.0),
title: Text(set["title"]),
selected: _selected[index],
onTap: () => setState(() => _selected[index] = !_selected[index]),
);
},
);
} else {
return Center(
child: new CircularProgressIndicator(),
);
}
},
);
} else {
return Text("loadin");
}
},
);
}
}
And this is the user profile:
class UserProfileState extends State<UserProfile> {
#override
Widget build(BuildContext context) {
return SliverList(
delegate: SliverChildListDelegate(
[
_mySetsLists(context),
Divider(),
StreamBuilder<FirebaseUser>(
stream: FirebaseAuth.instance.onAuthStateChanged,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.active) {
FirebaseUser user = snapshot.data;
if (user == null) {
return Text('not logged in');
}
return ListTile(
leading: CircleAvatar(
backgroundImage: NetworkImage(
user.photoUrl,
),
),
title: Text(user.displayName),
subtitle: Text(user.email),
trailing: new IconButton(
icon: new Icon(Icons.exit_to_app),
highlightColor: Colors.pink,
onPressed: () {
authService.signOut();
}),
);
} else {
return Text("loading profile"); // <---- THIS IS WHAT I SEE
}
},
),
],
),
);
}
I also went through the same difficulty, but this is the trick i used
var itemsData = List<dynamic>();
var _documents = List<DocumentSnapshot>();
#override
void initState() {
// TODO: implement initState
super.initState();
getData();
}
getData(){
Firestore.instance
.collection('users')
.document(currentUser.uid)
.collection('set')
.getDocuments()
.then((value) {
value.documents.forEach((result) {
setState(() {
_documents.add(result);
itemsData.add(result.data);
});
});
});
}
replace your listview builder will be like this
ListView.builder(
shrinkWrap: true,
itemCount: _documents.length,
itemBuilder: (context, index) {
return ListTile(
title:Text(itemsData[index]['name'])
)
})
Hope it helps!!
If you pretend to use setstat a lot using the stream you can download the data locally. So every reload will not download data again, but just show the local data.
First step: declare the variable that will store data locally.
QuerySnapshot? querySnapshotGlobal;
Then where you read the streamData, first check if the local data you just declared is empty:
//check if its empty
if(querySnapshotGlobal==null)
//as its empty, we will download it from firestore
StreamBuilder<QuerySnapshot>(
stream: _queryAlunos.snapshots(),
builder: (context, stream){
if (stream.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
}
else if (stream.hasError) {
return Center(child: Text(stream.error.toString()));
}
else if(stream.connectionState == ConnectionState.active){
//QuerySnapshot? querySnapshot = stream.data;
//instead of save data here, lets save it in the variable we declared
querySnapshotGlobal = stream.data;
return querySnapshotGlobal!.size == 0
? Center(child: Text('Sem alunos nesta turma'),)
: Expanded(
child: ListView.builder(
itemCount: querySnapshotGlobal!.size,
itemBuilder: (context, index){
Map<String, dynamic> map = querySnapshotGlobal!.docs[index].data();
//let it build
return _listDeAlunoswid(map, querySnapshotGlobal!.docs[index].id);
},
),
);
}
return CircularProgressIndicator();
},
)
else
//now, if you call setstate, as the variable with the data is not empty, will call it from here e instead of download it again from firestore, will load the local data
Expanded(
child: ListView.builder(
itemCount: querySnapshotGlobal!.size,
itemBuilder: (context, index){
Map<String, dynamic> map = querySnapshotGlobal!.docs[index].data();
return _listDeAlunoswid(map, querySnapshotGlobal!.docs[index].id);
},
),
),
Hope it helps you save some money!