Search Items are not showing up during search in SearchBar in Flutter? - flutter

I want to add Search Bar in Flutter. And I have achieved the state where I can type content in the search bar but during writing the query the List is not updating.
I want to sort on basis of blogName and below is the code
class AllBlogs extends StatefulWidget {
AllBlogs({Key key}) : super(key: key);
final Color _tabBackgroudColor = const Color(0xFF1A237E);
#override
AllBlogsState createState() {
return new AllBlogsState();
}
}
class AllBlogsState extends State<AllBlogs> {
Widget appBarTitle = Text("Blog's List");
Icon actionIcon = Icon(Icons.search, color: Colors.white,);
final key = new GlobalKey<ScaffoldState>();
final TextEditingController _searchQuery = new TextEditingController();
bool _IsSearching;
String _searchText = "";
_SearchListState() {
_searchQuery.addListener(() {
if (_searchQuery.text.isEmpty) {
setState(() {
_IsSearching = false;
_searchText = "";
});
}
else {
setState(() {
_IsSearching = true;
_searchText = _searchQuery.text;
});
}
});
}
#override
void initState() {
// TODO: implement initState
super.initState();
_IsSearching = false;
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: buildBar(context),
body: new Container(
color: Colors.transparent,
child: ListView.builder(
itemCount: allblogs.length,
// Facing Issue Here
itemBuilder: _IsSearching ? buildSearchList : blogslist
),
),
);
}
// Facing Issue Here
Widget buildSearchList(BuildContext context, int index){
if (_searchText.isEmpty){
return blogslist(context, index);
}
else {
List<String> _searchList = List();
for (int i = 0; i < allblogs.length; i++) {
String name = (allblogs[index].blogName);
if (name.toLowerCase().contains(_searchText.toLowerCase())) {
_searchList.add(name);
}
}
// Now what can i return to show the tile whoes blogName I searched for
);
}
}
Widget buildBar(BuildContext context) {
return AppBar(
centerTitle: true,
title: appBarTitle,
backgroundColor: widget._tabBackgroudColor,
actions: <Widget>[
IconButton(icon: actionIcon,
onPressed: () {
setState(() {
if (this.actionIcon.icon == Icons.search) {
// ignore: new_with_non_type
this.actionIcon = new Icon(Icons.close, color: Colors.white,);
this.appBarTitle = TextField(
controller: _searchQuery,
style: TextStyle(
color: Colors.white,
),
decoration: InputDecoration(
prefixIcon: new Icon(Icons.search, color: Colors.white),
hintText: "Search...",
hintStyle: TextStyle(color: Colors.white)
),
);
_handleSearchStart();
}
else {
_handleSearchEnd();
}
});
},),
],
);
}
void _handleSearchStart() {
setState(() {
_IsSearching = true;
});
}
void _handleSearchEnd() {
setState(() {
// ignore: new_with_non_type
this.actionIcon = new Icon(Icons.search, color: Colors.white,);
this.appBarTitle = new Text("Search Sample", style: TextStyle(
color: Colors.white,
),);
_IsSearching = false;
_searchQuery.clear();
});
}
}
Widget blogslist(BuildContext context, int index){
return Container(
padding: const EdgeInsets.only(top: 5.0),
child: Column(
children: <Widget>[
ListTile(
leading: Padding(
padding: const EdgeInsets.all(3.0),
child: new Image(image: AssetImage("assets/images/icons/stackexchange.png")),
),
title: Text(allblogs[index].blogName,
),
subtitle: Text(allblogs[index].blogName),
contentPadding: EdgeInsets.symmetric(horizontal: 3.0),
isThreeLine: true,
trailing: Padding(padding: const EdgeInsets.only(left: 5.0),
child: IconButton(icon: Icon(Icons.launch, color: Colors.blue, size: 20.0,),
onPressed: (){}),
),
),
Divider(),
],
),
);
}
All I want is to search the ListTile widget in the flutter based on the title
You can also see the image which I uploaded that shows I achieved the situation in which I can type something in the search bar. Now I just need to compare the input text with the ListTile's title, and show the matched tiles.
I have created a list in different class like----
class AllBlogs {
final String id;
final String blogName;
final String blogurl;
final String about;
const AllBlogs(
{#required this.id,
#required this.blogName,
#required this.blogurl,
#required this.about});
}
List<AllBlogs> allblogs = [
const AllBlogs(
id: '1',
blogName: 'KDnuggets',
blogurl: "https://www.kdnuggets.com/?ref=cybrhome",
about: "KDnuggets is one of the most popular data science blogs, with articles that cover Business Analytics, Statistics, and Machine Learning.",
),
and when I am trying to write below code then at place of allblogs.It's showing an error of 'a value of type List can't be assigned to a variable of type List class.

You have a List<Blog> somewhere called allblogs. Each time the search text changes form a new sublist as follows:
List<Blog> sublist = allblogs.where((b) => b.name.toLowerCase().contains(_searchText.toLowerCase())).toList();
(if search text is empty then simply assign allblogs to sublist)
Now use sublist everywhere you currently use allblogs in your builds.
So, on every change to the search criterion, you filter the full list down to the sub list that matches and (as long as you do that in setState) the Widget tree redraws showing just the filtered list.
Here's a complete working example based on your snippet above:
import 'package:flutter/material.dart';
main() {
runApp(new MaterialApp(
title: 'Blogs Test',
home: new AllBlogs(),
));
}
class Blog {
String blogName;
Blog(this.blogName);
}
List<Blog> allblogs = [
Blog('flutter'),
Blog('dart'),
Blog('java'),
Blog('python'),
];
class AllBlogs extends StatefulWidget {
AllBlogs({Key key}) : super(key: key);
final Color _tabBackgroundColor = const Color(0xFF1A237E);
#override
AllBlogsState createState() => AllBlogsState();
}
class AllBlogsState extends State<AllBlogs> {
Widget appBarTitle = Text("Blog's List");
Icon actionIcon = Icon(
Icons.search,
color: Colors.white,
);
final key = new GlobalKey<ScaffoldState>();
final TextEditingController _searchQuery = new TextEditingController();
List<Blog> _displayList = allblogs;
#override
void initState() {
super.initState();
_searchQuery.addListener(() {
if (_searchQuery.text.isEmpty) {
setState(() {
_displayList = allblogs;
});
} else {
setState(() {
String s = _searchQuery.text;
_displayList = allblogs
.where((b) => b.blogName.toLowerCase().contains(s.toLowerCase()))
.toList();
});
}
});
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: buildBar(context),
body: new Container(
color: Colors.transparent,
child: ListView.builder(
itemCount: _displayList.length,
itemBuilder: _blogBuilder,
),
),
);
}
Widget _blogBuilder(BuildContext context, int index) {
return Container(
padding: const EdgeInsets.only(top: 5.0),
child: Column(
children: <Widget>[
ListTile(
leading: Padding(
padding: const EdgeInsets.all(3.0),
child: new Image(
image: AssetImage("assets/images/icons/stackexchange.png")),
),
title: Text(_displayList[index].blogName),
subtitle: Text(_displayList[index].blogName),
contentPadding: EdgeInsets.symmetric(horizontal: 3.0),
isThreeLine: true,
trailing: Padding(
padding: const EdgeInsets.only(left: 5.0),
child: IconButton(
icon: Icon(
Icons.launch,
color: Colors.blue,
size: 20.0,
),
onPressed: () {}),
),
),
Divider(),
],
),
);
}
Widget buildBar(BuildContext context) {
return AppBar(
centerTitle: true,
title: appBarTitle,
backgroundColor: widget._tabBackgroundColor,
actions: <Widget>[
IconButton(
icon: actionIcon,
onPressed: () {
setState(() {
if (this.actionIcon.icon == Icons.search) {
this.actionIcon = new Icon(
Icons.close,
color: Colors.white,
);
this.appBarTitle = TextField(
controller: _searchQuery,
style: TextStyle(
color: Colors.white,
),
decoration: InputDecoration(
prefixIcon: new Icon(Icons.search, color: Colors.white),
hintText: "Search...",
hintStyle: TextStyle(color: Colors.white)),
);
} else {
this.actionIcon = new Icon(
Icons.search,
color: Colors.white,
);
this.appBarTitle = new Text(
"Search Sample",
style: TextStyle(
color: Colors.white,
),
);
_searchQuery.clear();
}
});
},
),
],
);
}
}

Related

My Flutter ListView is always removing the last item from the list

I'm creating a Flutter Widget and when I try to remove an item from the list I'm using, it always removes the last one, I was thinking it could be a Key problem, but nothing suits it, do anyone know how I could solve this?
The code
create_game.dart
import 'package:flutter/material.dart';
import 'package:pontinho/components/custom_input.dart';
class CreateGame extends StatefulWidget {
const CreateGame({super.key});
#override
State<CreateGame> createState() => _CreateGameState();
}
class _CreateGameState extends State<CreateGame> {
List<String> names = [''];
void changeName(int nameIndex, String change) {
setState(() {
names[nameIndex] = change;
});
}
void removeName(int nameIndex) {
print(names);
print(nameIndex);
setState(() {
names.removeAt(nameIndex);
});
}
ListView createNamesInput() {
return ListView.builder(
itemCount: names.length,
shrinkWrap: true,
itemBuilder: (context, index) {
return ListTile(
key: ObjectKey(index),
title: CustomInput(
key: ObjectKey(index),
labelText: "Nome",
onChanged: (String changed) => changeName(index, changed),
text: names[index],
onRemoved: () => removeName(index),
),
);
},
);
// return names
// .asMap()
// .entries
// .map((el) => CustomInput(
// key: ObjectKey('${el.key}'),
// labelText: "Nome",
// onChanged: changeName,
// index: el.key,
// text: names[el.key],
// onRemoved: removeName,
// ))
// .toList();
}
void addName() {
setState(() {
names.add('');
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: GestureDetector(
onTap: (() => Navigator.pop(context)),
child: const Icon(
Icons.arrow_back,
color: Colors.black,
size: 40,
),
),
backgroundColor: Colors.white,
titleTextStyle: const TextStyle(
color: Colors.black,
fontSize: 20,
),
title: const Text("CRIE SEU JOGO"),
),
body: Padding(
padding: const EdgeInsets.symmetric(
vertical: 8,
horizontal: 16,
),
// child: createNamesInput(),
child: Column(
children: [
createNamesInput(),
Padding(
padding: const EdgeInsets.symmetric(vertical: 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextButton(
onPressed: addName,
child: Row(
children: const [
Icon(Icons.add),
Text('Adicionar Jogador'),
],
),
),
],
),
),
SizedBox(
width: double.infinity,
height: 50,
child: ElevatedButton(
onPressed: () => print('Iniciar!'),
child: const Text('Iniciar!'),
),
)
],
),
),
);
}
}
custom_input.dart
import 'package:flutter/material.dart';
typedef OneArgumentCallback = void Function(String changed);
class CustomInput extends StatefulWidget {
final OneArgumentCallback onChanged;
final VoidCallback onRemoved;
final String labelText;
final String text;
const CustomInput({
super.key,
required this.onChanged,
required this.labelText,
required this.text,
required this.onRemoved,
});
#override
State<CustomInput> createState() => _CustomInputState();
}
class _CustomInputState extends State<CustomInput> {
late final TextEditingController inputController;
#override
void initState() {
super.initState();
inputController = TextEditingController(text: widget.text);
}
void changeContent(String value) {
widget.onChanged(
value,
);
}
#override
Widget build(BuildContext context) {
return TextFormField(
key: widget.key,
controller: inputController,
textDirection: TextDirection.ltr,
decoration: InputDecoration(
border: const UnderlineInputBorder(),
labelText: widget.labelText,
suffixIcon: IconButton(
onPressed: () => widget.onRemoved(),
icon: const Icon(
Icons.close,
color: Colors.red,
),
),
),
autocorrect: false,
onChanged: (value) => changeContent(value),
);
}
}
Indeed it is a key issue, you have to create a combined key that must be unique for each item, I merged the index with names[index],
CustomInput(
key: ObjectKey('$index:${names[index]}'),
labelText: "Nome",
onChanged: (String changed) => changeName(index, changed),
text: names[index],
onRemoved: () => removeName(index),
),
note that if you try this code alone the textfield will lose focus because the key has changed, this will be solved by removing the setState inside the onChange
void changeName(int nameIndex, String change) {
names[nameIndex] = change;
}
here you don't need setState because the UI will be updated by default when you are typing in the textfield
I hope I made it clear
I was thinking it could be a Key problem
That's correct; You need to use names[index] as the value for your Key:
ListTile(
key: ObjectKey(names[index]),
title: CustomInput(

How to pass a entire list to a new page

I have been trying to pass a entire List to a new page but a receiver this error " Exception has occurred. RangeError (RangeError (index): Invalid value: Valid value range is empty: 0) ". I believe the problem is on the page that is sending the list, since the error is apparently because the list is empty, right?
This is the code of my page that a sending the List:
import 'package:flutter/material.dart';
import 'package:flutter_cont`enter code here`ador/main.dart';
import 'package:flutter_contador/view/LeitorEAN_View.dart';
import 'package:sqflite/sqflite.dart';
import 'package:flutter_contador/data/produto.dart';
class ListaDeProdutos extends StatefulWidget {
final Future<Database>? database;
const ListaDeProdutos({Key? key, this.database}) : super(key: key);
#override
State<StatefulWidget> createState() {
return _ListaDeProdutosState();
}
}
class _ListaDeProdutosState extends State<ListaDeProdutos> {
List<Produto> listaproduto = List.empty(growable: true);
#override
void initState() {
fetchProdutos();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: const Text('Produto'),
bottom: AppBar(
automaticallyImplyLeading: false,
elevation: 0,
title: Container(
width: double.infinity,
height: 40,
color: Colors.white,
child: const Center(
child: TextField(
// controller: _controller,
decoration: InputDecoration(
prefixIcon: Icon(Icons.search),
// hintText: (Get.put(LeitorCodigoBarrasControle()).valorCodigoBarras),
hintText: ('Buscar...'),
),
),
),
),
),
),
body: ListView.builder(
itemCount: listaproduto.length,
itemBuilder: (context, index,) {
return Card(
child: ListTile(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => LeitorCodigoBarras(database: database, listaproduto: [],)),
);
}, // alterar quantidade do produto com leitor EAN
onLongPress: (){openUpdateProdutoView(index);}, // alterar quantidade do produto manualmente
// onLongPress: (){ deleteRecord(listaproduto[index]);}, // deletar o produto
leading: Text(listaproduto[index].codigo,style: const TextStyle(fontSize: 25)),
subtitle: Column(
children: [
Text(listaproduto[index].descricao,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: const TextStyle(fontSize: 16)
),
Text(listaproduto[index].codigoEAN,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: const TextStyle(fontSize: 16)),
],
),
trailing: Text(listaproduto[index].quantidade.toString(),style: const TextStyle(fontSize: 20)),
));
}),
);
}
void fetchProdutos() async {
final db = await widget.database;
final List<Map<String, dynamic>> maps =
await db!.query(Produto.tableName);
var list = List.generate(maps.length, (i) {
return Produto(
id: maps[i]['id'],
codigo: maps[i]['codigo'],
descricao: maps[i]['descricao'],
codigoEAN: maps[i]['codigoEAN'],
quantidade: maps[i]['quantidade'],
);
});
setState(() {
listaproduto.clear();
listaproduto.addAll(list);
});
}
// void deleteRecord(Produto produto) async {
// final db = await widget.database;
// db!.delete(Produto.tableName,
// where: 'id = ?', whereArgs: [produto.id]);
//
// fetchProdutos();
// }
void openUpdateProdutoView(int index) async {
bool doUpdate = await Navigator.pushNamed(context, "/updateProduto",
arguments: listaproduto[index]) as bool;
if (doUpdate) {
fetchProdutos();
}
}
}
This is the code of my page that a receiving the List:
import 'package:flutter/material.dart';
import 'package:flutter_contador/data/Produto.dart';
import 'package:scan/scan.dart';
import 'package:sqflite/sqflite.dart';
class LeitorCodigoBarras extends StatefulWidget {
const LeitorCodigoBarras(
{Key? key, required this.database, required this.listaproduto})
: super(key: key);
final Future<Database>? database;
final List<Produto> listaproduto;
#override
_LeitorCodigoBarrasState createState() => _LeitorCodigoBarrasState();
}
class _LeitorCodigoBarrasState extends State<LeitorCodigoBarras> {
List<Produto> listaproduto = List.empty(growable: true);
ScanController controller = ScanController();
var quantidadeEditController = TextEditingController();
var index = 0;
var quantidade = 0;
var scanResult = '';
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
toolbarHeight: 80,
title: const Text(
'Leitor EAN',
textAlign: TextAlign.center,
),
elevation: 0.0,
backgroundColor: const Color(0xFF333333),
leading: GestureDetector(
onTap: () => Navigator.of(context).pop(),
child: const Center(
child: Icon(
Icons.cancel,
color: Colors.white,
)),
),
actions: [
IconButton(
icon: const Icon(Icons.save),
onPressed: () {
}),
IconButton(
icon: const Icon(Icons.flashlight_on),
onPressed: () {
controller.toggleTorchMode();
})
],
),
body: Column(
children: [
SizedBox(
height: 400,
child: ScanView(
controller: controller,
scanAreaScale: .7,
scanLineColor: const Color.fromARGB(255, 51, 255, 0),
onCapture: (data) {
setState(() {
scanResult = data;
for (var i = 0; i < listaproduto.length; i++) {
if (listaproduto[i].codigoEAN == scanResult) {
index = i;
}else{
ScaffoldMessenger.of(context)
..removeCurrentSnackBar()
..showSnackBar(const SnackBar(content: Text("Código EAN não encontrado.")));
}
}
});
controller.resume();
},
),
),
SingleChildScrollView(
child: ListTile(
title: Text(
'Produto ${widget.listaproduto[index].codigo}',
textAlign: TextAlign.center,
style: TextStyle(color: Colors.black, fontSize: 40),
),
subtitle: Text(
'0000000',
textAlign: TextAlign.center,
),
),
),
const SizedBox(
child: ListTile(
title: Text(
'10',
textAlign: TextAlign.center,
),
leading: Icon(Icons.add),
trailing: Icon(Icons.remove),
),
),
],
),
);
}
}
You pass your list as an argument to a named route, but you do not take the argument anywhere on the page where you receive the list.
Inside your build add this to receive the list:
List<Produto> list = ModalRoute.of(context)!.settings.arguments as List<Produto>;
See here: https://docs.flutter.dev/cookbook/navigation/navigate-with-arguments

Listview.builder not updating after inserting new data

I'm having troubles with my list builder.
I'm trying to add more TextFormFields when the "+" button next to the "Tag" text is pressed, I'm fetching the tag list from firebase and then displaying every tag from that list in a separate TextFormField, but when I try to add a new TextFormField with the "+" button, nothing happens, I check if the list leght changes and indeed it changes, but nothing happens, what I would expect is to get a new TextFormField in the red square.
code:
import 'package:flutter/material.dart';
import '../database/firestoreHandler.dart';
import '../models/todo2.dart';
import '../widgets/dialogs.dart';
class TodoEdit extends StatefulWidget {
String? doctitle;
String? doctdescription;
String? docimage;
String? docid;
List? doctags;
TodoEdit({Key? key, this.doctitle, this.doctdescription, this.docimage, this.docid,this.doctags}) : super(key: key);
#override
_TodoEditState createState() => _TodoEditState();
}
// -----------------------------my widget------------
Widget tagForm(controller){
return TextFormField(
controller: controller,
style: TextStyle(color: Colors.white),
decoration: InputDecoration(
labelText: "Tag",
labelStyle: TextStyle(color: Colors.white60),
fillColor: Colors.black,
filled: true,
),
);
}
//---------------------------------------------------
class _TodoEditState extends State<TodoEdit> {
final _formKey = GlobalKey<FormState>();
final tcontroller = TextEditingController();
final dcontroller = TextEditingController();
final icontroller = TextEditingController();
//--------------------add widget to list----------------
void _addformWidget(list,controller) {
setState(() {
list.add(tagForm(controller));
});
}
//------------------------------------------------
#override
void initState() {
super.initState();
tcontroller.text = widget.doctitle.toString();
dcontroller.text = widget.doctdescription.toString();
icontroller.text = widget.docimage.toString();
}
#override
Widget build(BuildContext context) {
//----------I add the tags to the list view for the first time-----
var textEditingControllers = <TextEditingController>[];
var textformFields = <Widget>[];
widget.doctags?.forEach((element) {
var textEditingController = new TextEditingController(text: element);
textEditingControllers.add(textEditingController);
//return textformFields.add(tagForm(textEditingController)
return _addformWidget(textformFields, textEditingController);
//);
});
//------------------------------------------
return Scaffold(
backgroundColor: Colors.grey[900],
appBar: AppBar(
actions: [
IconButton(onPressed: (){
showDialog(
barrierDismissible: false,
context: context,
builder: (context) {
return AlertDialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
title: Text('Delete TODO'),
actions: [
TextButton(
child: Text('Cancel'),
onPressed: () {
Navigator.pop(context);
},
),
TextButton(
child: Text('Delete'),
onPressed: () {
deleteData(widget.docid.toString(), context);
setState(() {
showSnackBar(context, 'todo "${widget.doctitle}" successfully deleted!');
});
},
),
],
);
},
);
},
icon: Icon(Icons.delete))
],
backgroundColor: Colors.grey[900],
title: Text("${widget.doctitle}"),
),
body: Container(
child: SafeArea(
child: Form(
key: _formKey,
child: Column(
children: [
SizedBox(height: 10),
TextFormField(
controller: tcontroller,
style: TextStyle(color: Colors.white),
decoration: InputDecoration(
labelText: "Title",
labelStyle: TextStyle(color: Colors.white60),
fillColor: Colors.black,
filled: true,
),
),
SizedBox(height: 10),
TextFormField(
controller: dcontroller,
style: TextStyle(color: Colors.white),
decoration: InputDecoration(
labelText: "Description",
labelStyle: TextStyle(color: Colors.white60),
fillColor: Colors.black,
filled: true,
),
),
SizedBox(height: 10),
TextFormField(
controller: icontroller,
style: TextStyle(color: Colors.white),
decoration: InputDecoration(
labelText: "Image url",
labelStyle: TextStyle(color: Colors.white60),
fillColor: Colors.black,
filled: true,
),
),
SizedBox(height: 10),
Row(children: [
Text("Tags:", style:TextStyle(color: Colors.white)),
//-----------------------here I try to add the new text form field-----------
IconButton(onPressed: (){
var textEditingController = new TextEditingController(text: "tag");
textEditingControllers.add(textEditingController);
_addformWidget(textformFields,textEditingController);
print(textformFields.length);
},
icon: Icon(Icons.add,color: Colors.white,),
)
],),//------------------------
/*SingleChildScrollView(
child: new Column(
children: textformFields,
)
),*/
//--------------------------------here I build my list--------------
Expanded(
child: SizedBox(
height: 200.0,
child: ListView.builder(
itemCount: textformFields.length,
itemBuilder: (context,index) {
return textformFields[index];
}),
)
),
],
),
),
),
),
//--------------------------------------------------
floatingActionButton: FloatingActionButton(
onPressed: (){
if(tcontroller == '' && dcontroller == '' && icontroller == ''){
print("not valid");
}else{
var todo = Todo2(
title: tcontroller.text,
description: dcontroller.text,
image: icontroller.text,
//tags: tagcontroller.text,
);
updateData(todo, widget.docid.toString(),context);
setState(() {
showSnackBar(context, 'todo ${widget.doctitle} successfully updated!');
});
}
},
child: Icon(Icons.update),
),
);
}
}
Any help appreciated!
Since you've kept the list of form fields and controllers in the build function, the widget isn't rebuilt when you call setState on them.
Instead move these to with other state variables.
final _formKey = GlobalKey<FormState>();
final tcontroller = TextEditingController();
final dcontroller = TextEditingController();
final icontroller = TextEditingController();
final textEditingControllers = <TextEditingController>[];
final textformFields = <Widget>[];
Now you can change the _addformWidget function to directly use the list without taking it as a parameter.
void _addformWidget(TextEditingController controller) {
setState(() {
textformFields.add(tagForm(controller));
});
}
Then initialise them in the initState function.
#override
void initState() {
super.initState();
tcontroller.text = widget.doctitle.toString();
dcontroller.text = widget.doctdescription.toString();
icontroller.text = widget.docimage.toString();
widget.doctags?.forEach((element) {
final textEditingController = new TextEditingController(text: element);
textEditingControllers.add(textEditingController);
//return textformFields.add(tagForm(textEditingController)
_addformWidget(textEditingController);
//);
});
}
This ideally should fix your problem. Let me know if it doesn't and if it does, you can click the check mark to confirm that.
//// Remove textEditingControllers and textformFields list from the build. And declare it on top.
#override
Widget build(BuildContext context) {
//----------I add the tags to the list view for the first time-----
var textEditingControllers = <TextEditingController>[];
var textformFields = <Widget>[];
//// Use like below
class _TodoEditState extends State<TodoEdit> {
final _formKey = GlobalKey<FormState>();
final tcontroller = TextEditingController();
final dcontroller = TextEditingController();
final icontroller = TextEditingController();
var textEditingControllers = <TextEditingController>[]; //<---------
var textformFields = <Widget>[];
////// Full Code
class TodoEdit extends StatefulWidget {
String? doctitle;
String? doctdescription;
String? docimage;
String? docid;
List? doctags;
TodoEdit(
{Key? key,
this.doctitle,
this.doctdescription,
this.docimage,
this.docid,
this.doctags})
: super(key: key);
#override
_TodoEditState createState() => _TodoEditState();
}
class _TodoEditState extends State<TodoEdit> {
final _formKey = GlobalKey<FormState>();
final tcontroller = TextEditingController();
final dcontroller = TextEditingController();
final icontroller = TextEditingController();
var textEditingControllers = <TextEditingController>[];
var textformFields = <Widget>[];
#override
void initState() {
widget.doctags?.forEach((element) {
var textEditingController = TextEditingController(text: element);
textEditingControllers.add(textEditingController);
//return textformFields.add(tagForm(textEditingController)
return _addformWidget(textformFields, textEditingController);
//);
});
super.initState();
tcontroller.text = widget.doctitle.toString();
dcontroller.text = widget.doctdescription.toString();
icontroller.text = widget.docimage.toString();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey[900],
appBar: AppBar(
actions: [
IconButton(
onPressed: () {
showDialog(
barrierDismissible: false,
context: context,
builder: (context) {
return AlertDialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
title: Text('Delete TODO'),
actions: [
TextButton(
child: Text('Cancel'),
onPressed: () {
Navigator.pop(context);
},
),
TextButton(
child: Text('Delete'),
onPressed: () {
deleteData(widget.docid.toString(), context);
setState(() {
showSnackBar(context,
'todo "${widget.doctitle}" successfully deleted!');
});
},
),
],
);
},
);
},
icon: Icon(Icons.delete))
],
backgroundColor: Colors.grey[900],
title: Text("${widget.doctitle}"),
),
body: Container(
child: SafeArea(
child: Form(
key: _formKey,
child: Column(
children: [
SizedBox(height: 10),
TextFormField(
controller: tcontroller,
style: TextStyle(color: Colors.white),
decoration: InputDecoration(
labelText: "Title",
labelStyle: TextStyle(color: Colors.white60),
fillColor: Colors.black,
filled: true,
),
),
SizedBox(height: 10),
TextFormField(
controller: dcontroller,
style: TextStyle(color: Colors.white),
decoration: InputDecoration(
labelText: "Description",
labelStyle: TextStyle(color: Colors.white60),
fillColor: Colors.black,
filled: true,
),
),
SizedBox(height: 10),
TextFormField(
controller: icontroller,
style: TextStyle(color: Colors.white),
decoration: InputDecoration(
labelText: "Image url",
labelStyle: TextStyle(color: Colors.white60),
fillColor: Colors.black,
filled: true,
),
),
SizedBox(height: 10),
Row(
children: [
Text("Tags:", style: TextStyle(color: Colors.white)),
//-----------------------here I try to add the new text form field-----------
IconButton(
onPressed: () {
var textEditingController =
new TextEditingController(text: "tag");
textEditingControllers.add(textEditingController);
_addformWidget(textformFields, textEditingController);
print(textformFields.length);
},
icon: Icon(
Icons.add,
color: Colors.white,
),
)
],
), //------------------------
/*SingleChildScrollView(
child: new Column(
children: textformFields,
)
),*/
//--------------------------------here I build my list--------------
Expanded(
child: SizedBox(
height: 200.0,
child: ListView.builder(
itemCount: textformFields.length,
itemBuilder: (context, index) {
return textformFields[index];
}),
)),
],
),
),
),
),
//--------------------------------------------------
floatingActionButton: FloatingActionButton(
onPressed: () {
if (tcontroller == '' && dcontroller == '' && icontroller == '') {
print("not valid");
} else {
var todo = Todo2(
title: tcontroller.text,
description: dcontroller.text,
image: icontroller.text,
//tags: tagcontroller.text,
);
updateData(todo, widget.docid.toString(), context);
setState(() {
showSnackBar(
context, 'todo ${widget.doctitle} successfully updated!');
});
}
},
child: Icon(Icons.update),
),
);
}
//--------------------add widget to list----------------
void _addformWidget(list, controller) {
setState(() {
list.add(tagForm(controller));
});
}
// -----------------------------my widget------------
Widget tagForm(controller) {
return TextFormField(
controller: controller,
style: TextStyle(color: Colors.white),
decoration: InputDecoration(
labelText: "Tag",
labelStyle: TextStyle(color: Colors.white60),
fillColor: Colors.black,
filled: true,
),
);
}
}

I dont want to display all the records of table in listview but I want to display records of only particular customer in flutter

I have a screen which shows list of customers using listview. Next when I click on a customer I want to show the notes(records) only of that particular customer(customerId) in next screen in listview. I know how to display all the records of table. but how to display only certain records?? Neither there is any error nor the listview is being displayed. I dont know where am I going wrong.
List<CustomerNote> cnoteList;
int count = 0;
if (cnoteList == null) {
cnoteList = List<CustomerNote>();
updateCustomerNotes();
}
db_service.dart
Future<List<CustomerNote>> getCustomerNotes(int customer) async {
await DB.init();
var res = await DB.rawQuery("noteDetails WHERE custId = '$customer'");
int count = res.length;
List<CustomerNote> cnotelist = List<CustomerNote>();
for (int i = 0; i < count; i++) {
cnotelist.add(CustomerNote.fromMap(res[i]));
}
return cnotelist;
}
People_List.dart //this is the file which displays list of customers
import 'package:customer/models/Note.dart';
import 'package:customer/models/addCustomer.dart';
import 'package:customer/screens/New_Note.dart';
import 'package:customer/screens/Note_info.dart';
import 'package:customer/screens/User_Settings.dart';
import 'package:customer/screens/add_person.dart';
import 'package:customer/services/db_service.dart';
import 'package:customer/utils/database_helper.dart';
import 'package:flutter/material.dart';
import 'dart:io';
import 'package:sqflite/sqflite.dart';
class People_List extends StatefulWidget{
#override
State<StatefulWidget> createState() {
return People_ListState();
}
}
class People_ListState extends State<People_List> with SingleTickerProviderStateMixin{
DBService dbService = DBService();
List<AddCustomer> customerList;
int count = 0;
static final GlobalKey<ScaffoldState> scaffoldKey = new GlobalKey<ScaffoldState>();
var _isSelectedItemIndex;
TextEditingController _searchQuery;
bool _isSearching = false;
String searchQuery = "Search query";
#override
void initState() {
super.initState();
_searchQuery = new TextEditingController();
}
void _startSearch() {
print("open search box");
ModalRoute
.of(context)
.addLocalHistoryEntry(new LocalHistoryEntry(onRemove: _stopSearching));
setState(() {
_isSearching = true;
});
}
void _stopSearching() {
_clearSearchQuery();
setState(() {
_isSearching = false;
});
}
void _clearSearchQuery() {
print("close search box");
setState(() {
_searchQuery.clear();
updateSearchQuery("Search query");
});
}
Widget _buildTitle(BuildContext context) {
var horizontalTitleAlignment =
Platform.isIOS ? CrossAxisAlignment.center : CrossAxisAlignment.start;
return new InkWell(
onTap: () => scaffoldKey.currentState.openDrawer(),
child: new Padding(
padding: const EdgeInsets.symmetric(horizontal: 12.0),
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: horizontalTitleAlignment,
children: <Widget>[
const Text(''),
],
),
),
);
}
Widget _buildSearchField() {
return new TextField(
controller: _searchQuery,
autofocus: true,
decoration: const InputDecoration(
hintText: 'Search...',
border: InputBorder.none,
hintStyle: const TextStyle(color: Colors.white30),
),
style: const TextStyle(color: Colors.white, fontSize: 16.0),
onChanged: updateSearchQuery,
);
}
void updateSearchQuery(String newQuery) {
setState(() {
searchQuery = newQuery;
});
print("search query " + newQuery);
}
List<Widget> _buildActions() {
if (_isSearching) {
return <Widget>[
new IconButton(
icon: const Icon(Icons.clear),
onPressed: () {
if (_searchQuery == null || _searchQuery.text.isEmpty) {
Navigator.pop(context);
return;
}
_clearSearchQuery();
},
),
];
}
return <Widget>[
new IconButton(
icon: const Icon(Icons.search),
onPressed: _startSearch,
),
];
}
#override
Widget build(BuildContext context) {
var height = MediaQuery.of(context).size.height;
var width = MediaQuery.of(context).size.width;
if (customerList == null) {
customerList = List<AddCustomer>();
updateListView();
}
return Scaffold(
appBar: new AppBar(
leading: _isSearching ? const BackButton() : null,
title: _isSearching ? _buildSearchField() : _buildTitle(context),
actions: _buildActions(),
),
body:getCustomerListView(),
floatingActionButton: FloatingActionButton(
onPressed: () {
navigateToCustomer(AddCustomer(), 'Add Person');
},
child: const Icon(Icons.add),
),
bottomNavigationBar:Row (
children: <Widget>[
buildNavBarItem(Icons.home,0,"Home"),
buildNavBarItem(Icons.fiber_new_rounded,1,"Upcoming"),
buildNavBarItem(Icons.history,2,"History"),
buildNavBarItem(Icons.account_circle,3,"Account"),
],
),
);
}
ListView getCustomerListView() {
TextStyle titleStyle = Theme.of(context).textTheme.subhead;
return ListView.builder(
itemCount: count,
itemBuilder: (BuildContext context, int position) {
return Card(
color: Colors.white,
elevation: 2.0,
child: ListTile(
/*trailing: CircleAvatar(
backgroundColor: getPriorityColor(this.noteList[position].priority),
child: getPriorityIcon(this.noteList[position].priority),
),*/
title: Text(this.customerList[position].custName, style: titleStyle,),
//subtitle: Text(this.customerList[position].date),
onTap: () {
},
),
);
},
);
}
void navigateToCustomer(AddCustomer customer, String title) async {
bool result = await Navigator.push(context, MaterialPageRoute(builder: (context) {
return AddPerson(customer, title);
}));
if (result == true) {
updateListView();
}
}
void updateListView() {
final Future<Database> dbFuture = DB.init();
dbFuture.then((database) {
Future<List<AddCustomer>> customerListFuture = dbService.getCustomerList();
customerListFuture.then((customerList) {
setState(() {
this.customerList = customerList;
this.count = customerList.length;
});
});
});
}
Widget buildNavBarItem(IconData icon,int index,title) {
var height = MediaQuery.of(context).size.height;
var width = MediaQuery.of(context).size.width;
return GestureDetector(
onTap: () {
setState(() {
_isSelectedItemIndex=index;
if(_isSelectedItemIndex==3) {
Navigator.of(context).push(MaterialPageRoute(
builder: (BuildContext context) => User_Settings()));
}
});
},
child: Container(
height: height * 0.09,
width: width / 4,
decoration: index==_isSelectedItemIndex?BoxDecoration(
border: Border(
bottom: BorderSide(width: 4,color: Theme.of(context).primaryColor),
),
gradient: LinearGradient(colors: [
Theme.of(context).primaryColor.withOpacity(0.3),
Theme.of(context).primaryColor.withOpacity(0.015),
],begin: Alignment.bottomCenter,end: Alignment.topCenter)
):BoxDecoration(),
child: Column(
children: <Widget>[
InkWell(
child: Icon(icon,
color: index==_isSelectedItemIndex? Theme.of(context).primaryColor:Colors.black54,
),
),
Text(title)
],)),
);
}
}
Note_Info.dart
class Note_Info extends StatefulWidget{
final String appBarTitle;
final AddCustomer customer;
Note_Info(this. customer, this.appBarTitle);
#override
State<StatefulWidget> createState() {
return Note_InfoState(this.customer,this.appBarTitle);
}
}
class Note_InfoState extends State<Note_Info> {
CustomerNote note=CustomerNote();
DBService dbService = DBService();
List<CustomerNote> cnoteList;
int count = 0;
String appBarTitle;
AddCustomer customer;
Note_InfoState(this.customer, this.appBarTitle);
PickedFile _imageFile;
final ImagePicker _picker = ImagePicker();
bool rememberMe = false;
DateTime _date = DateTime.now();
TextEditingController custNameController = TextEditingController();
void getImage(ImageSource source) async {
final pickedFile = await _picker.getImage(
source: source);
setState(() {
_imageFile = pickedFile;
});
}
#override
Widget build(BuildContext context) {
if (noteList == null) {
noteList = List<CustomerNote>();
updateCustomerNotes();
}
var height = MediaQuery.of(context).size.height;
custNameController.text = customer.custName;
return DefaultTabController(
length: 4,
child: Scaffold(
appBar: AppBar(
actions: [
IconButton(
icon: Icon(
Icons.add,
),
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (BuildContext context) => NewNote()));
},
)
],
),
body: Container(
child: Column(
children: <Widget>[
TextField(controller: custNameController,
style: TextStyle(
fontSize: 20.0, fontWeight: FontWeight.bold),
textAlign: TextAlign.center),
Padding(
padding: const EdgeInsets.all(15.0),
child: Row(children: [
ImageProfile(),
Padding(
padding: const EdgeInsets.only(left: 30.0),
child: IconButton(
icon: Icon(
Icons.call,
color: Colors.green,
size: 45,
),
onPressed: () {
},
),
),
],),
),
SizedBox(
height: 50,
child: AppBar(
bottom: TabBar(
tabs: [
Tab(
text: "All",
),
Tab(
text: "Pending",
),
Tab(
text: "Cancelled",
),
Tab(
text: "Completed",
),
],
),
),
),
// create widgets for each tab bar here
Expanded(
child: TabBarView(
children: [
// first tab bar view widget
Container(
child: getNoteListView(),
),
// second tab bar view widget
Container(
child: Center(
child: Text(
'Pending Items',
),
),
),
Container(
child: Center(
child: Text(
'Cancelled',
),
),
),
Container(
child: Center(
child: Text(
'Completed',
),
),
),
],
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
height: 55.0,
width: 200,
child: RaisedButton(
elevation: 2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20)),
color: Theme
.of(context)
.primaryColorDark,
textColor: Colors.white,
child: Text('Save', textScaleFactor: 1.5,),
onPressed: () {
setState(() {
//_reset();
});
},
),
),
),
]
),
)
));
}
void updateCustomerNotes() {
final Future<Database> dbFuture = DB.init();
dbFuture.then((database) {
int customerId=customer.custId;
Future<List<CustomerNote>> noteListFuture = dbService.getCustomerNotes(customerId);
noteListFuture.then((cnoteList) {
setState(() {
this.cnoteList = cnoteList;
//this.count = cnoteList.length;
});
});
});
}
ListView getNoteListView() {
TextStyle titleStyle = Theme.of(context).textTheme.subhead;
return ListView.builder(
itemCount: count,
itemBuilder: (BuildContext context, int position) {
return Card(
color: Colors.white,
elevation: 2.0,
child: ListTile(
title: Text(this.cnoteList[position].note, style: titleStyle,),
subtitle: Text(this.cnoteList[position].date),
trailing: GestureDetector(
child: Icon(Icons.delete, color: Colors.grey,),
onTap: () {
},
),
onTap: () {
},
),
);
},
);
}
void _showSnackBar(BuildContext context, String message) {
final snackBar = SnackBar(content: Text(message));
Scaffold.of(context).showSnackBar(snackBar);
}
Widget ImageProfile() {
return Center(
child: CircleAvatar(
radius: 80.0,
backgroundImage: AssetImage('images/person_icon.jpg')
),
);
}
}
If u want to get some specific data from the server then you need to provide (where: ) in your query such as
List<Map> result = await db.query(
DatabaseHelper.table,
columns: columnsToSelect,
where: whereString,
whereArgs: whereArguments);
// print the results
result.forEach((row) => print(row));
// {_id: 1, name: Bob, age: 23}
}
Note your query can be different from the above one.
and if you want to get the same specific data from already fetched data then also you need to use the where clause such as
final outData = responseData.where((i) => i.userId == customerId).toList();
and then pass the outData to next page through params.

'This expression has a type of 'void' so its value can't be used.' setState() error flutter

I am getting the error quoted above when I try to rebuild a class. The class I am calling, ListOfIngs(), is a class that basically creates a textField, but my goal is to create a large amount of TextFields, the variable countIngs holds the value for the exact number, in a listView. Here is the code:
class NewGroceryList extends State<NewGroceryListWidget> {
final GlobalKey<_ListOfIngsState> _key = GlobalKey();
final myController = new TextEditingController();
int countings = 0;
Widget build(BuildContext context) {
debugPrint(myController.text);
return Scaffold(
appBar: AppBar(
title: Text("New Grocery List"),
leading: IconButton(
icon: const Icon(Icons.arrow_back_ios, color: Colors.white),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => ListsPage()),
);
},
),
actions: <Widget>[
IconButton(
icon: new Icon(Icons.check, color: Colors.white),
onPressed: () {})
],
),
drawer: AppDrawer(),
body: Container(
padding: EdgeInsets.fromLTRB(10.0, 20.0, 10.0, 30.0),
child: Column(
children: <Widget>[
Row(
children: <Widget>[
Text('Ingredients',
style: GoogleFonts.biryani(fontSize: 15.0)),
IconButton(
icon: new Icon(Icons.add),
onPressed: () {
setState(() {
countings++;
});
debugPrint('$countings');
},
)
],
),
setState(() {
ListOfIngsWidget(countings);
}),
],
),
));
}
}
Here is the ListOfIngs class/Widget:
class ListOfIngsWidget extends StatefulWidget {
final int countIngs;
const ListOfIngsWidget(this.countIngs, {Key key}) : super(key: key);
#override
_ListOfIngsState createState() => _ListOfIngsState();
}
class _ListOfIngsState extends State<ListOfIngsWidget> {
List<TextEditingController> _controllerList = [];
List<TextField> _textFieldList = [];
#override
void initState() {
for (int i = 1; i <= widget.countIngs; i++) {
TextEditingController controller = TextEditingController();
TextField textField = TextField(
controller: controller,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Ingredient $i',
),
);
_textFieldList.add(textField);
_controllerList.add(controller);
}
super.initState();
}
#override
Widget build(BuildContext context) {
return new Container(
child: Flexible(
child: ListView(children: _textFieldList),
),
);
}
}
Remove the setState around the ListOfIngsWidget and add a UniqueKey() to it like so:
ListOfIngsWidget(countings, key: UniqueKey()).