Can't get the ID of a record in Firebase Firestore - Getting the last document only - flutter

I am not finding the right solution to my problem since several weeks already.
I have two collections.
One is named Inbox the other one is named Area_of_focus.
In Inbox, I have several documents. In the document, I have a field called AOF_Name and AOF_ID.
When I create a new document into Inbox, on my view, I have a dropdown button containing all the records from the collection Area_of_focus.
The user must select one of the record so it is assigned to the document created into Inbox.
If I can get the name of AOF, I am not able to get the right ID. I am getting the ID of the last document. I do not understand what I am missing.
I have tried to implement the solution proposed below, but I guess I am not doing it right.
Please, can you help? Many thanks.
second option using a map
import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
String myProjectName = '';
var selectedProject = '';
var selectedID = '';
DocumentSnapshot? snap;
DocumentSnapshot? snapShot;
List idAOF2 = [];
List NameAOF2 = [];
Map<String,String> MD = {};
//#########################################################################
String selectedProjectCapture = '';
String selectedContextCapture = '';
String selectedFocusCapture = '';
//##########################################################################
class CaptureV2 extends StatefulWidget {
const CaptureV2({Key? key}) : super(key: key);
#override
_CaptureV2State createState() => _CaptureV2State();
}
class _CaptureV2State extends State<CaptureV2> {
final GlobalKey<FormState> _captureFormKey = GlobalKey<FormState>();
String? selectedProjectCapture = '', selectedFocusCapture = '';
TextEditingController? _controllerTaskName;
TextEditingController? _controllerMyGoal;
String? _valueTaskNameChanged = '';
String? _valueTaskNameSaved = '';
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
double height = MediaQuery.of(context).size.height;
return Material(
child: Scaffold(
appBar: AppBar(
centerTitle: true,
title: const Text('TEMP'),
actions: const <Widget>[
Padding(
padding: EdgeInsets.fromLTRB(0, 22, 0, 0),
child: Text("TEST"),
),
],
),
body: SingleChildScrollView(
child: Column(children: [
Form(
key: _captureFormKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Container(
decoration: const BoxDecoration(
border: Border(
top: BorderSide(width: 1.0, color: Colors.grey),
),
),
),
//Test
Theme(
data: ThemeData(
inputDecorationTheme: const InputDecorationTheme(
border: InputBorder.none,
)),
child: Card(
child: Padding(
padding: const EdgeInsets.fromLTRB(
8.0, 0.0, 15.0, 1.0),
child: TextFormField(
decoration: const InputDecoration(
hintText: "Task Name",
hintStyle:
TextStyle(color: Color(0xff29B6F6)),
),
keyboardType: TextInputType.text,
maxLength: 100,
maxLines: 3,
onChanged: (valTaskName) => setState(
() => _valueTaskNameChanged = valTaskName),
validator: (valTaskName) {
return valTaskName!.isEmpty
? "Task name cannot be empty"
: null;
},
onSaved: (valTaskName) => setState(
() => _valueTaskNameSaved = valTaskName),
),
),
)),
//Project
Theme(
data: ThemeData(
inputDecorationTheme: const InputDecorationTheme(
border: InputBorder.none,
)),
child: Padding(
padding:
const EdgeInsets.fromLTRB(8.0, 3.0, 0.0, 0.0),
child: StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance
.collection('Users')
.doc(FirebaseAuth.instance.currentUser!.uid)
.collection('projects')
.snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
const Text("Loading.....");
} else {
List<DropdownMenuItem> projectItems = [];
List<String> idProject = [];
for (int i = 0;
i < snapshot.data!.docs.length;
i++) {
DocumentSnapshot snap =
snapshot.data!.docs[i];
idProject.add(snap.id);
projectItems.add(
DropdownMenuItem(
value: (snap['project_Name'] + snap.id),
child: SizedBox(
width: MediaQuery.of(context)
.size
.width *
0.89,
child: Text(
(snap['project_Name'] +
'---' +
snap.id),
style: const TextStyle(
color: Colors.black,
fontSize: 16),
),
),
),
);
}
return Row(children: <Widget>[
DropdownButton(
items: projectItems,
onChanged: (dynamic myProject) {
setState(() {
selectedProjectCapture = myProject;
});
},
// value: selectedProjectCapture,
isExpanded: false,
hint: SizedBox(
width: MediaQuery.of(context).size.width * 0.89,
height: 40.0,
child: selectedProjectCapture == ''
? const Text(
'Project ?',
style: TextStyle(
color: Color(0xff29B6F6),
fontSize: 16),
)
: Text(
selectedProjectCapture!,
style: const TextStyle(
color: Colors.black,
fontSize: 16),
)
//projectName
),
)
]);
}
return Container(
height: 0,
width: 0,
);
}),
),
),
//#########AOF
Theme(
data: ThemeData(
inputDecorationTheme: const InputDecorationTheme(
border: InputBorder.none, //OutlineInputBorder(),
)),
child: Padding(
padding:
const EdgeInsets.fromLTRB(8.0, 3.0, 0.0, 0.0),
child: StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance
.collection('Users')
.doc(FirebaseAuth.instance.currentUser!.uid)
.collection('area_of_Focus')
.snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
const Text("Loading.....");
} else {
List<DropdownMenuItem> projectItems = [];
for (int i = 0;
i < snapshot.data!.docs.length;
i++) {
DocumentSnapshot snapShot = snapshot.data!.docs[i];
AOF({'id':snapShot.id,'name':snapShot['name']});
AOF(MD).mapAOF.addAll({'id':snapShot.id,'name':snapShot['name']});
projectItems.add(
DropdownMenuItem(
value: MD['name'],//(snapShot['name']),
child: Text(MD['name']!,
//(snapShot['name']),
style: const TextStyle(
color: Colors.black),
),
),
);
}
return Row(
mainAxisAlignment:
MainAxisAlignment.start,
children: <Widget>[
DropdownButton(
icon: const Icon(
Icons.arrow_downward_outlined),
items: projectItems,
onChanged: (dynamic myFocus) {
setState(() {
selectedFocusCapture = myFocus;
print((MD['name']));
print ('id selected');
print (MD['id']);
// var SnapshotID = snapShot?.id;
// var index =
// NameAOF2.indexOf(myFocus);
// print(idAOF2[index]);
});
},
isExpanded: false,
hint: SizedBox(
width: MediaQuery.of(context).size.width * 0.89,
height: 40.0,
child: selectedFocusCapture == ''
? const Text(
'Area of focus ?',
style: TextStyle(
color:
Color(0xff29B6F6)),
)
: Text(
selectedFocusCapture!,
style: const TextStyle(
color: Colors
.black), //projectName
),
),
)
],
);
}
return Container(
height: 0,
width: 0,
);
}),
)),
],
)),
//bottomNavigationBar: MyBottomAppBar(),
]))));
}
}
class AOF {
Map <String, String> mapAOF ={'id':'','name':''};
AOF(this.mapAOF);
}

The key is that you should be able to tell what is the name of an AOF by its ID. To do that, you need a map (or better, a dedicated class). A Map a simple list of key-value pairs. It looks like this :
var aofMap = {
'aofId1': 'aofName1',
'aofId2': 'aofName2',
}
Then you'll be able to do aofMap['aofId1'] to retrieve 'aofName1'.
So instead of only keeping the id in the AOF2 list, turn it into a Map<String, String> and do this :
DocumentSnapshot snapShot = snapshot.data!.docs[i];
AOF2[snapShot.id] = snapShot.name;
With a custom class (useful if you have more data than 1), you would use a Map<String, CustomClass> and write a static fromMap(Map<String, dynamic>) method in CustomClass to convert the incoming data into a CustomClass object. Better yet, you can use the integrated withConverter method to do it for you.

Related

Display searched Item base on user input

I'm trying to display a result item following the user input in the text field, but I receive all the items. There were some methods I tried, but they didn't work and I encountered some errors.
here is my source code
import 'dart:convert';
import 'package:ebook_flutter_app/constant.dart';
import 'package:ebook_flutter_app/model/image.dart';
import 'package:ebook_flutter_app/model/text_value.dart';
import 'package:ebook_flutter_app/screens/show_item.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:persistent_bottom_nav_bar/persistent-tab-view.dart';
import '../widgets/showImage.dart';
class SearchScreen extends StatefulWidget {
const SearchScreen({Key? key}) : super(key: key);
#override
SearchScreenState createState() => SearchScreenState();
}
class SearchScreenState extends State<SearchScreen> {
List textValues = [];
List original = [];
List result = [];
TextEditingController txtQuery = TextEditingController();
List<TextValue> textValueList = [];
List<MyImage> myImageList = [];
List<TextValue> getCatList(List<TextValue> inputList, String query) {
List<TextValue> outputList =
inputList.where((item) => item.title == query).toList();
//textValueList = outputList;
//var myList = outputList;
return outputList;
}
List<MyImage> getImageList(List<MyImage> inputList, String query) {
List<MyImage> outputList =
inputList.where((o) => o.id_num!.toString() == query).toList();
// myImageList = outputList;
return outputList;
}
#override
void initState() {
super.initState();
txtQuery.addListener(() {
if (isNumeric(txtQuery.text) == true) {
loadImage();
searchById(txtQuery.text);
print('I\'m using search option for loading Image.... ');
} else {
loadData();
search(txtQuery.text);
print('I\'m using search option for loading Data....');
}
});
}
void loadData() async {
String jsonStr = await rootBundle.loadString('assets/db/text_value.json');
var json = jsonDecode(jsonStr);
textValues = json;
original = json;
setState(() {});
}
void loadImage() async {
String jsonStr = await rootBundle.loadString('assets/db/image_db.json');
var json = jsonDecode(jsonStr);
textValues = json;
original = json;
print('load Image is running....');
setState(() {});
}
void search(String query) {
if (query.isEmpty) {
textValues = original;
setState(() {});
return;
}
query = query.toLowerCase();
print(query);
//List result = [];
textValues.forEach((element) {
var name = element["name"].toString().toLowerCase();
var description = element["description"].toString().toLowerCase();
if (name.contains(query) || description.contains(query)) {
result.add(element);
// textValueList.add(element);
// print('textValueList is $textValueList');
}
});
textValues = result;
setState(() {});
}
void searchById(String query1) {
if (query1.isEmpty) {
textValues = original;
print('query1 is .....$query1');
setState(() {});
return;
}
print('query1 is $query1');
//List result = [];
textValues.forEach((element) {
var id_num = element["id_num"].toString();
var img_num = element["img_num"].toString();
if (id_num.contains(query1)) {
result.add(element);
// myImageList.add(element);
// print('mYImageList is $myImageList');
print('result is......$result');
}
});
textValues = result;
print('textValues is .....$textValues');
setState(() {});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: CustomAppBar(2),
body: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
margin: const EdgeInsets.all(10),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextFormField(
controller: txtQuery,
onChanged: (value) {
setState(() {});
},
textDirection: TextDirection.rtl,
decoration: InputDecoration(
hintText: "جست وجو...",
hintTextDirection: TextDirection.rtl,
hintStyle: TextStyle(
color: Colors.black,
fontSize: 18,
fontFamily: 'iran-sans-ds',
decoration: TextDecoration.none,
fontStyle: FontStyle.italic,
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(4.0)),
focusedBorder: const OutlineInputBorder(
borderSide: BorderSide(color: Colors.black)),
prefixIcon: const Icon(Icons.search),
suffixIcon: IconButton(
icon: const Icon(Icons.clear),
onPressed: () {
txtQuery.text = '';
txtQuery.clear();
},
),
),
keyboardType: TextInputType.text,
),
],
),
),
txtQuery.text.isEmpty
? Container()
: Expanded(
child: ListView.builder(
itemCount: textValues.length,
// isNumeric(txtQuery.text) == true
// ? getImageList(myImageList, txtQuery.text).length
// : getCatList(textValueList, txtQuery.text).length,
itemBuilder: (context, index) {
var textVal = textValues[index];
String description = textVal['description'] ??
'we don\'t have description......';
var id_num = textVal['id_num'].toString() ??
'we don\'t have id_num......';
var img_num = textVal['img_num'].toString() ??
'we don\'t have img_num........... ';
print('id_num is ....$id_num'
' img_num is.....$img_num');
return Card(
margin:
const EdgeInsets.fromLTRB(8.0, 4.0, 8.0, 4.0),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0)),
color: Colors.blue[50],
child: Theme(
data: Theme.of(context)
.copyWith(dividerColor: Colors.transparent),
child: InkWell(
onTap: (() => pushNewScreen(
context,
screen: isNumeric(id_num) == false
? ShowItem(
name: textVal['name'],
description:
textVal['description'],
)
: ShowImage(
title: id_num,
image: Myasset(img_num),
),
withNavBar:
true, // OPTIONAL VALUE. True by default.
pageTransitionAnimation:
PageTransitionAnimation.slideRight,
)),
child: ExpansionTile(
title: Text(
isNumeric(id_num) == false
? textVal['name']
: id_num,
textDirection: TextDirection.rtl,
style: const TextStyle(
fontSize: 20.0, color: Colors.black54),
),
childrenPadding: const EdgeInsets.only(
bottom: 20.0,
right: 20.0,
left: 20.0,
top: 5.0),
children: [
isNumeric(id_num) == false
? Row(
mainAxisAlignment:
MainAxisAlignment.spaceAround,
children: [
const Text(
'بیشتر',
textDirection:
TextDirection.rtl,
textAlign: TextAlign.justify,
style: TextStyle(
color: Colors.blue,
fontWeight:
FontWeight.bold),
),
Text(
'${description.substring(0, 39)} ...',
textDirection:
TextDirection.rtl,
textAlign: TextAlign.justify,
style: TextStyle(
color: Colors.black),
),
])
: Image.asset(
Myasset(img_num),
fit: BoxFit.cover,
width: MediaQuery.of(context)
.size
.width *
0.01,
height: MediaQuery.of(context)
.size
.height *
0.01,
),
],
),
),
),
);
}),
)
]),
);
}
}
Widget _listView(text_value) {
return Expanded(
child: ListView.builder(
itemCount: text_value.length,
itemBuilder: (context, index) {
var textVal = text_value[index];
String description =
textVal['description'] ?? 'we don\'t have description......';
var id_num =
textVal['id_num'].toString() ?? 'we don\'t have id_num......';
var img_num = textVal['img_num'].toString() ??
'we don\'t have img_num........... ';
print('id_num is ....$id_num' ' img_num is.....$img_num');
return Card(
margin: const EdgeInsets.fromLTRB(8.0, 4.0, 8.0, 4.0),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0)),
color: Colors.blue[50],
child: Theme(
data:
Theme.of(context).copyWith(dividerColor: Colors.transparent),
child: InkWell(
onTap: (() => pushNewScreen(
context,
screen: isNumeric(id_num) == false
? ShowItem(
name: textVal['name'],
description: textVal['description'],
)
: ShowImage(
title: id_num,
image: Myasset(img_num),
),
withNavBar: true, // OPTIONAL VALUE. True by default.
pageTransitionAnimation:
PageTransitionAnimation.slideRight,
)),
child: ExpansionTile(
title: Text(
isNumeric(id_num) == false ? textVal['name'] : id_num,
textDirection: TextDirection.rtl,
style:
const TextStyle(fontSize: 20.0, color: Colors.black54),
),
childrenPadding: const EdgeInsets.only(
bottom: 20.0, right: 20.0, left: 20.0, top: 5.0),
children: [
isNumeric(id_num) == false
? Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
const Text(
'بیشتر',
textDirection: TextDirection.rtl,
textAlign: TextAlign.justify,
style: TextStyle(
color: Colors.blue,
fontWeight: FontWeight.bold),
),
Text(
'${description.substring(0, 39)} ...',
textDirection: TextDirection.rtl,
textAlign: TextAlign.justify,
style: TextStyle(color: Colors.black),
),
])
: Image.asset(
Myasset(img_num),
fit: BoxFit.cover,
width: MediaQuery.of(context).size.width * 0.01,
height: MediaQuery.of(context).size.height * 0.01,
),
],
),
),
),
);
}),
);
}
I didn't use getCatList & myImageListmethods because I encountered to error when I was using this methods.
How can I fix it?
Inside addListener you're calling loadData() every single time the user enter a character. Try this:
void initState() {
super.initState();
loadData();
txtQuery.addListener(() {
search(txtQuery.text);
});
}
The second thing you could try is use for in instead of forEach
void search(String query) {
if (query.isEmpty) {
textValues = [];
setState(() {});
return;
}
setState(() {
textValues = [
for (var item in yourDataSource)
if (item['key'].contains(query)) item
];
});
}
And you can use textValues in your list
body: ListView.builder(
itemCount: textValues.length,
You can use autocomplete textfield for your problem
check this plugin :
https://pub.dev/packages/auto_complete_search
You don't have any function for onChanged (TextFormField's argument), let's try this:
First edit your search() function
void search(String query) {
if (query.isEmpty) {
setState(() {
textValues = original;
});
return;
}
setState(() {
textValues = original.where( (element) =>
element['name'].contains(query.toLowerCase()).toString().toLowerCase() ||
element['description'].contains(query.toLowerCase()).toString().toLowerCase()
).toList();
});
}
Second edit onChanged argument
onChanged: (value) => search(value)

Keyboard trigger the api call while closing and opening in flutter?

Keyboard triggers the api calling while closing and opening
I have search bar I didn't pass anything inside the search bar but when I click the search bar The api call will run.
I don't know why that thing was happen I tried several ways but It won't work
Even Inside the keyboard I choose the one hand keyboard that time also api will run
Also tried the Focusnode also.
class PopupNaviagator extends StatefulWidget {
var body;
String leadsName = "";
Map<String, dynamic> listValues;
PopupNaviagator(this.listValues);
var data;
String pageData = "";
double totalPageCount = 0;
int pageIncrementer = 1;
#override
_PopupNavigatorState createState() => _PopupNavigatorState();
}
class _PopupNavigatorState extends State<PopupNaviagator> {
Utils util = new Utils();
bool isSearching = false;
#override
void initState() {
super.initState();
}
String searchingText = "";
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
titleSpacing: 0,
flexibleSpace: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: util.getColors(1001),
stops: [0.1, 5.0],
),
),
),
title: !isSearching
? Text("Select Search Type")
: TextField(
autofocus: true,
autocorrect: true,
onChanged: (value) {
searchingText = value;
},
cursorColor: Colors.white,
onSubmitted: (value) {
searchingText = value;
campaignAPI(
widget.listValues["colname"].toString(),
widget.pageIncrementer.toString(),
searchingText, // search key
1, // flag
);
},
style: TextStyle(color: Colors.white),
decoration: InputDecoration(
icon: Icon(Icons.search),
hintText: "Search ",
hintStyle: TextStyle(color: Colors.white)),
),
actions: <Widget>[
isSearching
? IconButton(
icon: Icon(Icons.cancel),
onPressed: () {
setState(() {
searchingText = "";
this.isSearching = false;
campaignAPI(
widget.listValues["colname"].toString(),
widget.pageIncrementer.toString(),
searchingText, // search key
1, // flag
);
/* filteredCountries = countries;*/
});
},
)
: IconButton(
icon: Icon(Icons.search),
onPressed: () {
setState(() {
this.isSearching = true;
});
},
)
],
),
body: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.all(Radius.circular(5))),
child: Scaffold(
body: FutureBuilder(
future: campaignAPI(widget.listValues["colname"].toString(), "1",
searchingText, 0),
builder: (context, snapshot) {
if (snapshot.hasData) {
var body;
if (widget.data == null) {
body = snapshot.data;
} else {
body = widget.data;
}
final records = body["list_records"];
widget.pageData = body["PageValues"];
widget.totalPageCount =
(body["TotalRecordCount"] / 5).toDouble();
return Scaffold(
body: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
if (records.length != 0) ...[
Expanded(
child: ListView.builder(
padding: EdgeInsets.only(
top: 0,
bottom: 0,
),
physics: ClampingScrollPhysics(),
shrinkWrap: true,
itemCount: records.length,
itemBuilder: (context, index) {
Map<String, dynamic> pickerValues =
records[index];
String titleName =
pickerValues["viewcol_value"]
.toString();
return Container(
margin: const EdgeInsets.all(5.00),
decoration: new BoxDecoration(
color: Colors.white,
border: Border.all(
color: Colors.grey, width: 1.0),
borderRadius: new BorderRadius.all(
Radius.circular(3.0)),
),
child: FlatButton(
padding: EdgeInsets.all(8.0),
onPressed: () {
setState(() {
List<String> strArr = [
titleName,
pickerValues["rec_id"].toString(),
widget.listValues["colname"]
];
Navigator.pop(context, strArr);
});
},
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(titleName.toString()),
Icon(
Icons.check_circle_outlined,
color: Colors.grey,
),
]),
),
);
}),
),
] else ...[
Container(
height: MediaQuery.of(context).size.height / 1.4,
child: Center(
child: Container(
padding: EdgeInsets.all(65),
child: Text(
"No Record Found",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 20,
color: Colors.black),
),
decoration: BoxDecoration(
border: Border.all(
color: Colors.grey,
width: 2,
),
)),
),
),
],
if (records.length != 0) ...[
Container(
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
InkWell(
onTap: () {
if (widget.pageIncrementer > 1) {
widget.pageIncrementer--;
campaignAPI(
widget.listValues["colname"]
.toString(),
widget.pageIncrementer.toString(),
searchingText, // search key
1, // flag
);
setState(() {});
} else {
util.showToast("No records to show");
}
},
child: Icon(Icons.arrow_left_rounded,
size: 50, color: Colors.white),
),
Text(
widget.pageData,
style: TextStyle(
fontSize: 15,
color: Colors.white,
fontWeight: FontWeight.bold),
),
InkWell(
onTap: () {
if (widget.totalPageCount > 1 &&
widget.totalPageCount >=
widget.pageIncrementer) {
widget.pageIncrementer++;
campaignAPI(
widget.listValues["colname"]
.toString(),
widget.pageIncrementer.toString(),
searchingText, // search key
1, // flag
);
} else {
util.showToast("No reocrds to show");
}
},
child: Icon(Icons.arrow_right_rounded,
size: 50, color: Colors.white),
),
],
),
decoration: BoxDecoration(
gradient: LinearGradient(
colors: util.getColors(1001),
stops: [0.1, 5.0],
),
),
)
]
],
),
),
);
} else if (snapshot.hasError) {
return Text('${snapshot.error.toString()}');
}
return Center(
child: CircularProgressIndicator(),
);
},
),
),
));
}
campaignAPI(
String field_col, String page_no, String searchValue, int flag) async {
Utils util = new Utils();
SharedPreferences prefs = await SharedPreferences.getInstance();
final accessKey = prefs.getString('access_key');
final companyName = prefs.getString('company_name');
Object requestParam = {
"companyname": companyName,
"access_key": accessKey.toString(),
"field_col": field_col,
"page_no": page_no,
"searchValue": searchValue,
};
print(requestParam.toString());
APIS apis = new APIS();
Uri url = Uri.parse(apis.searchquickcreate);
util.prints(url);
util.prints(requestParam);
final response = await http.post(url, body: requestParam);
if (response.statusCode == 200) {
final body = json.decode(response.body);
print(body);
String status = body["status"];
if (status != "failed") {
if (flag == 1) {
setState(() {
widget.data = body;
});
}
return body;
} else {
util.logOut(context);
return body;
}
} else {
Navigator.pop(context);
util.showToast("Server Error !");
throw Exception("Server Error !");
}
}
}

Rendering Filtered List in Flutter

I'm having trouble displaying a filtered list in my widget. It works up to the point of printing the filtered data in the list as per the query that is passed but not when that exact data needs to be displayed. I believe I will have to update the list with the filtered data every time I type in a query but I just cannot figure out how and where I need to use setState to update that. My code and the outputs are as follows:
Initially, the entire list gets rendered but the moment I type in a query string, the list is supposed to get modified with only the data that matched the query. This is not something that's happening at the moment. The list tends to remain as it is.
However, when I print the filtered data, it seems to work just fine(_searchResult printed in the searchData method below).
[
{product_id: 8, restaurant_name: Mocambo, restaurant_id: 6, product_name: Kaju Paneer, product_description: Tasty yummy paneer gravy dish, product_image: /public/assets/product/lgml5L03-19-41.jpg, product_selling_price: 320},
{product_id: 5, restaurant_name: City Club, restaurant_id: 1, product_name: Palak Paneer, product_description: Tasty silky gravy with goodness of palak, product_image: /public/assets/product/C6pGz101-42-17.jpg, product_selling_price: 180},
{product_id: 4, restaurant_name: City Club, restaurant_id: 1, product_name: Shahi Paneer, product_description: Tasty Paneer main course dish, product_image: /public/assets/product/vgI1dR01-29-18.jpg, product_selling_price: 240}
]
The code:
The method that filters. (Please note that the filtering is performed after the data is fetched from the server. For my convenience, I decided to convert it into a list)
class PopularDishesProvider with ChangeNotifier {
Map<String, dynamic> _dishes = {};
final List<dynamic> _searchDish = [];
List<dynamic> _searchResult = [];
List<dynamic> get searchDish {
return [..._searchDish];
}
List<dynamic> get searchResult {
return [..._searchResult];
}
Future<void> searchData(String query) async {
final url = Uri.parse(baseUrl + 'api/all_products');
final response = await http.get(url);
PopularDishes popularDishes = popularDishesFromJson(response.body); //This method converts the response into Dart model
_dishes = popularDishes.toJson();
_dishes['data'].forEach((value) => _searchDish.add(value));
_searchResult = _searchDish.where((element) {
final name = element['product_name'].toLowerCase();
final searchQuery = query.toLowerCase();
return name.contains(searchQuery);
}).toList();
print(_searchResult);
notifyListeners();
}
}
The widget where this is supposed to be rendered:
class SearchState extends State<Search> {
final _controller = TextEditingController();
bool value = true;
String query = '';
List<dynamic> search = [];
PopularDishesProvider popular = PopularDishesProvider();
#override
void initState() { //This is to make the API Call for the first time
// TODO: implement initState
Provider.of<PopularDishesProvider>(context, listen: false)
.searchData('');
});
super.initState();
}
#override
Widget build(BuildContext context) {
final height = MediaQuery.of(context).size.height;
final width = MediaQuery.of(context).size.width;
final textScale = MediaQuery.of(context).textScaleFactor * 1.2;
final searchProvider = Provider.of<PopularDishesProvider>(context).searchResult;
PopularDishesProvider popular = PopularDishesProvider();
// TODO: implement build
return Scaffold(
appBar: AppBar(
automaticallyImplyLeading: false,
elevation: 5,
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
// backgroundColor: Colors.green,
titleSpacing: 0,
toolbarHeight: 100,
title: Column(
children: [
Container(
width: double.infinity,
height: 40,
.......
.......
.......
),
Stack(
children: [
Container(
height: 60,
width: double.infinity,
// color: Colors.red,
padding: const EdgeInsets.only(top: 8, left: 2),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Icon(
Icons.search,
size: 30,
color: Colors.grey,
),
Expanded(
child: Center(
child: Container(
margin:
const EdgeInsets.only(bottom: 6, right: 4),
padding: const EdgeInsets.only(left: 6),
height: 45,
width: width * 0.7,
decoration: BoxDecoration(
borderRadius: const BorderRadius.all(
Radius.circular(14)),
border:
Border.all(color: Colors.grey, width: 2)),
child: Row(
children: [
Flexible(
flex: 9,
fit: FlexFit.tight,
child: Center(
child: TextField(
controller: _controller,
onChanged: (value) async {
setState(() {
query = value;
});
await popular.searchData(value);
},
autofocus: true,
cursorColor: Colors.grey,
style: const TextStyle(
color: Colors.grey, fontSize: 18),
decoration: const InputDecoration(
border: InputBorder.none,
hintText:
'Search By Restaurant or Food',
hintStyle:
TextStyle(color: Colors.grey),
),
),
)),
Flexible(
flex: 1,
fit: FlexFit.tight,
child: InkWell(
onTap: () => Navigator.of(context).pop(),
child: const Icon(Icons.close,
color: Colors.grey),
),
)
],
),
),
),
),
],
),
),
],
)
],
)),
body: Column(
children: [
Expanded(
child: Container(
width: double.infinity,
color: Colors.red,
child: ListView.builder(
itemBuilder: (context, index) => ListTile(
title: Text(searchProvider [index]['product_name'])),
itemCount: searchProvider.length,
),
)
)
],
),
);
}
}
Can someone please help out?

How to solve: type 'List<dynamic>' is not a subtype of type 'String' [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 2 years ago.
Improve this question
I want to update image from listofTaskNotApprove class which it will pass the object of documentsnapshot into the EditTaskNotApprove. Before I update the image, I need to display specific of image where the user will be select specific info from listofTaskNotApprove. The problem is how to display the current index of image into the new screen?
ListOfTaskNotAccepted class.
import 'package:carousel_pro/carousel_pro.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:fyp/screen/RecordOfficer/EditTaskNotApprove.dart';
import 'package:fyp/shared/Loading.dart';
import 'package:google_fonts/google_fonts.dart';
class ListOfTaskNotAccepted extends StatefulWidget {
#override
_ListOfTaskNotAcceptedState createState() => _ListOfTaskNotAcceptedState();
}
final FirebaseAuth auth = FirebaseAuth.instance;
Stream<QuerySnapshot> getUser(BuildContext context) async* {
final FirebaseUser rd = await auth.currentUser();
yield* Firestore.instance.collection("Task").where('uid',isEqualTo: rd.uid).where("verified", isEqualTo: 'TidakSah').snapshots();
}
class _ListOfTaskNotAcceptedState extends State<ListOfTaskNotAccepted> {
List<NetworkImage> _listOfImages = <NetworkImage>[];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Aduan Tidak Diterima"),
backgroundColor: Colors.redAccent,
),
body: Container(
child: StreamBuilder(
stream: getUser(context),
builder: (context, snapshot){
if (snapshot.hasError || !snapshot.hasData) {
return Loading();
} else{
return ListView.builder(
itemCount: snapshot.data.documents.length,
itemBuilder: (BuildContext context, int index){
DocumentSnapshot da = snapshot.data.documents[index];
_listOfImages =[];
for(int i =0; i <da['url'].length; i++){
_listOfImages.add(NetworkImage(da['url'][i]));
}
return Card(
child:ListTile(
title: Container(
alignment: Alignment.centerLeft,
child: Column(
children: <Widget>[
SizedBox(height: 5.0),
Container(alignment: Alignment.centerLeft,
child: Row(
children: [
Text("Sumber Aduan: ", style: GoogleFonts.asap(fontWeight: FontWeight.bold)),
Text(da['sumberAduan'], style: GoogleFonts.asap(fontWeight: FontWeight.bold)),
],
),
),
SizedBox(height: 5.0),
Container(alignment: Alignment.centerLeft,
child: Row(
children: [
Text("Nombor Aduan: ", style: GoogleFonts.lato(fontWeight: FontWeight.bold)),
Text(da['noAduan'], style: GoogleFonts.lato(fontWeight: FontWeight.bold)),
],
),
),
SizedBox(height: 5.0),
Container(alignment: Alignment.centerLeft,
child: Row(
children: [
Text("Lokasi: ", style: GoogleFonts.lato(fontWeight: FontWeight.bold)),
Text(da['kawasan'] + " " + da['naJalan'], style: GoogleFonts.lato(fontWeight: FontWeight.bold)),
],
),
),
SizedBox(height: 5.0),
Container(alignment: Alignment.centerLeft,
child: Row(
children: [
Text("Kategori: ", style: GoogleFonts.arimo(fontWeight: FontWeight.w500)),
Text(da['kategori'], style: GoogleFonts.arimo(fontWeight: FontWeight.w500)),
],
),
),
Column(
children: [
Container(
margin: EdgeInsets.all(10.0),
height: 200,
decoration: BoxDecoration(
color: Colors.white
),
width: MediaQuery.of(context).size.width,
child: Carousel(
boxFit: BoxFit.cover,
images: _listOfImages,
autoplay: false,
indicatorBgPadding: 5.0,
dotPosition: DotPosition.bottomCenter,
animationCurve: Curves.fastLinearToSlowEaseIn,
animationDuration: Duration(milliseconds: 2000),
),
)
],
)
],
),
),
subtitle: Container(
child: Column(
children: [
SizedBox(height: 5.0),
Container(alignment: Alignment.centerLeft,
child: Row(
children: [
Text("Catatan: ", style: GoogleFonts.arimo(fontWeight: FontWeight.w500)),
Text(da['comments'], style: GoogleFonts.arimo(fontWeight: FontWeight.w500)),
],
),
),
],
),
),
onTap: () {Navigator.push(context, MaterialPageRoute(builder: (context) => EditTask(da:da)));}
)
);
});
}
}),
)
);
}
}
Here is EditTask class which I need to display current index of image that selected by user.
import 'package:carousel_pro/carousel_pro.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
class EditTask extends StatefulWidget {
final DocumentSnapshot da;
const EditTask({Key key, this.da}) : super(key: key);
#override
_EditTaskState createState() => _EditTaskState(da);
}
class _EditTaskState extends State<EditTask> {
DocumentSnapshot da;
_EditTaskState(DocumentSnapshot da){
this.da = da;
}
TextEditingController _noAduan;
TextEditingController _sumberAduan;
TextEditingController _kategori;
DateTime myDateTime = DateTime.now();
#override
void initState(){
super.initState();
_noAduan = TextEditingController(text: widget.da.data['noAduan']);
_sumberAduan =TextEditingController(text: widget.da.data['sumberAduan']);
_kategori = TextEditingController(text: widget.da.data['kategori']);
myDateTime = (da.data['date']).toDate();
_listOfImages = NetworkImage(da.data['url']) as List<NetworkImage>; // this line show the error
}
List <String> sumber = <String> ['Sistem Aduan MBPJ', 'Sistem Aduan Waze', 'Sistem Aduan Utiliti'];
List <String> kate = <String> ['Segera', 'Pembaikan Biasa'];
String kategori;
String sumberAduan;
List <NetworkImage> _listOfImages = <NetworkImage>[];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Kemaskini Aduan"),
backgroundColor: Colors.redAccent,
),
body: Container(
padding: const EdgeInsets.all(16.0),
child: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
SizedBox(height: 10.0),
TextFormField(
decoration:InputDecoration(
hintText: myDateTime.toString(),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5))),
onChanged: (value){
setState(() {
myDateTime = value as DateTime;
print(myDateTime);
});
},
),
SizedBox(height: 10.0),
TextFormField(
decoration:InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5))),
controller: _noAduan,
),
SizedBox(height: 10.0),
DropdownButtonFormField(
hint:Text(widget.da.data['sumberAduan']),
decoration: InputDecoration(
prefixIcon: Icon(Icons.perm_contact_calendar),
border: OutlineInputBorder(borderRadius: BorderRadius.circular(5))),
isExpanded: true,
value: sumberAduan,
onChanged: (newValue) {
setState(() {
sumberAduan = newValue;
_sumberAduan.text = sumberAduan;
});
},
items: sumber.map((sum){
return DropdownMenuItem(
value: sum,
child: new Text(sum),
);
}).toList(),
),
SizedBox(height: 10.0),
DropdownButtonFormField(
hint:Text(widget.da.data['kategori']),
decoration: InputDecoration(
prefixIcon: Icon(Icons.perm_contact_calendar),
border: OutlineInputBorder(borderRadius: BorderRadius.circular(5))),
isExpanded: true,
value: kategori,
onChanged: (newValue) {
setState(() {
kategori = newValue;
_kategori.text = kategori;
});
},
items: kate.map((ka){
return DropdownMenuItem(
value: ka,
child: new Text(ka),
);
}).toList(),
),
Container(
margin: EdgeInsets.all(10.0),
height: 200,
decoration: BoxDecoration(
color: Colors.white
),
width: MediaQuery.of(context).size.width,
child: Carousel(
boxFit: BoxFit.cover,
autoplay: false,
//images: _listOfImages,
indicatorBgPadding: 5.0,
dotPosition: DotPosition.bottomCenter,
animationCurve: Curves.fastLinearToSlowEaseIn,
animationDuration: Duration(milliseconds: 2000),
),
)
],
),
),
)
);
}
}
the image that need to display for update image
This is how I want to display image in class EditTask when the user want to update information from ListOfTaskNotApprove
The error show that "type 'List' is not a subtype of type 'String'"
Can someone help me? because I had tried many method to solve this problem but it didn't work for me.
You say:
_listOfImages = NetworkImage(da.data['url']) as List<NetworkImage>; // this line show the error
Yes, you can't cast a NetworkImage to a List<NetworkImage>. You probably meant:
_listOfImages = [ NetworkImage(da.data['url']) ] as List<NetworkImage>;
The thing is your are getting a list of url's from Firebase storage which are Strings but you are adding this strings into a list of type Network Image which is wrong. As a list of string cannot be converted to a list of Network Image.
There are 2 ways to resolve this-
Change your list type to List and then wherever you show this image use
list data as an argument for Network Image.
List<String> urls=new List();
//suppose list is not empty
....
return NetworkImage(urls[i]);
....
While adding url's to your list add an Network Image object and directly use the list item while showing images.
List<NetworkImage> list=new List();
list.add(NetworkImage('some url'));
....
return list[i];
....

How to print multiple values from dynamic list in ... loop

Hy, im working on a project, using table_calendar plugin im receiving meetings record from database and showing them as a marker on the calendar, now i want to show that meeting details on the page in a list, but i don't have any idea how to do that, i able to print it meeting ids in the list, but how i can print other meetings details also, like location, time, customer name etc?
import 'package:flutter/material.dart';
import 'package:hexcolor/hexcolor.dart';
import 'package:intl/intl.dart';
import 'notifcation_dialog.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:table_calendar/table_calendar.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'variables.dart';
import 'package:flutter_datetime_picker/flutter_datetime_picker.dart';
import 'package:expandable/expandable.dart';
TextEditingController agendaController = new TextEditingController();
TextEditingController phoneController = new TextEditingController();
TextEditingController locationController = new TextEditingController();
meeting mee = new meeting();
meeting meet = new meeting();
String _time = '';
List meetDate;
CalendarController _controller;
String dateWithT;
String emailFromSharedPref, meetingAdded;
Map smData;
Map meetingDetail;
List meetingInfo, customerInfo;
List<dynamic> _selectedEvents;
Map<DateTime, List<dynamic>> _events;
Map<DateTime, List<dynamic>> c_nameMap;
class AddMeeting extends StatefulWidget {
#override
_AddMeetingeState createState() => _AddMeetingeState();
}
class _AddMeetingeState extends State<AddMeeting> {
#override
void initState() {
super.initState();
_controller = CalendarController();
_events = {};
_selectedEvents = [];
c_nameMap = {};
getIdAndGetMeetings();
}
Future getIdAndGetMeetings() async {
// getting email from SharedPreferences
SharedPreferences prefs = await SharedPreferences.getInstance();
emailFromSharedPref = prefs.getString('email');
// getting saleManager info using email
var url = "http://.../getSaleMangerDetal.php";
var response = await http.post(url, body: {
"m_email": emailFromSharedPref,
});
smData = jsonDecode(response.body);
// getting customer info using saleManagerID
var customerInfoUrl = "http://.../calender/getCustomerInfo.php";
var customerInfoResponse = await http.post(customerInfoUrl, body: {
"sm_id": smData['manager_id'],
});
// saving customer info in the list, because there are many dict in the list
customerInfo = jsonDecode(customerInfoResponse.body);
// get meetings details from server using saleManager Id
var getmeetingUrl = "http://.../getMeetings.php";
var getMeetiongResponse = await http.post(getmeetingUrl, body: {
"manager_id": smData['manager_id'],
});
meetingInfo = jsonDecode(getMeetiongResponse.body);
print(meetingInfo);
for (int i = 0; i < meetingInfo.length; i++) {
dateWithT =
meetingInfo[i]['m_date'].replaceAll(new RegExp(r'[^\w\s]+'), '');
dateWithT = dateWithT.replaceAll(' ', '');
dateWithT = dateWithT + "000000";
dateWithT = dateWithT.substring(0, 8) + 'T' + dateWithT.substring(8);
mee.dateTime = DateTime.parse(dateWithT);
if (_events[mee.dateTime] != null) {
_events[mee.dateTime].add(meetingInfo[i]['meeting_id']);
} else {
_events[mee.dateTime] = [meetingInfo[i]['meeting_id']];
}
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Flutter Calendar'),
),
body: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
// Text(_time),
TableCalendar(
events: _events,
// initialCalendarFormat: CalendarFormat.week,
calendarStyle: CalendarStyle(
canEventMarkersOverflow: true,
todayColor: Colors.orange,
selectedColor: Theme.of(context).primaryColor,
todayStyle: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 18.0,
color: Colors.white)),
headerStyle: HeaderStyle(
centerHeaderTitle: true,
formatButtonDecoration: BoxDecoration(
color: Colors.orange,
borderRadius: BorderRadius.circular(20.0),
),
formatButtonTextStyle: TextStyle(color: Colors.white),
formatButtonShowsNext: false,
),
startingDayOfWeek: StartingDayOfWeek.monday,
onDaySelected: (date, events) {
setState(() {
_selectedEvents = events;
});
},
builders: CalendarBuilders(
calendarController: _controller,
),
..._selectedEvents.map((event) => Stack(
children: <Widget>[
// getMeetingsIndividualDetails(event),
Card(
child: Container(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: ExpandablePanel(
header: Text(event),
// Text(getMeetingsIndividualDetails(event, 'c_name')),
collapsed: Text(
'qwe',
softWrap: true,
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
expanded: Text(
'as',
softWrap: true,
),
tapHeaderToExpand: true,
hasIcon: true,
),
),
),
),
],
)),
],
),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: _showAddDialog,
),
);
}
_showAddDialog() async {
await showDialog(
context: context,
builder: (context) => StatefulBuilder(builder: (context, setState) {
return ShowDialog();
}));
setState(() {
_selectedEvents = _events[mee.dateTime];
});
}
}
addMeetingToDatabase(List meetDate2) async {
// print(meetDate2[0]);
var getmeetingUrls = "http://.../addMeeting.php";
var getMeetiongResponses = await http.post(getmeetingUrls, body: {
"sm_id": smData['manager_id'],
"c_id": '2',
"agenda": agendaController.text,
"phone": phoneController.text,
"location": locationController.text,
"date": meetDate2[0],
"time": _time,
});
meetingAdded = jsonDecode(getMeetiongResponses.body);
print(meetingAdded);
}
class ShowDialog extends StatefulWidget {
#override
_ShowDialogState createState() => _ShowDialogState();
}
class _ShowDialogState extends State<ShowDialog> {
#override
Widget build(BuildContext context) {
return AlertDialog(
content: SingleChildScrollView(
child: Container(
// height: MediaQuery.of(context).size.height/3,
child: Column(
// mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 8.0, bottom: 8),
child: TextField(
controller: phoneController,
// maxLines: null,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Phone',
prefixIcon: Icon(Icons.phone_android),
labelStyle: TextStyle(fontSize: 15)),
),
),
Padding(
padding: const EdgeInsets.only(top: 8.0, bottom: 8),
child: TextField(
controller: locationController,
// maxLines: null,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Meeting Location',
prefixIcon: Icon(Icons.add_location),
labelStyle: TextStyle(fontSize: 15)),
),
),
Padding(
padding: const EdgeInsets.only(top: 8.0, bottom: 8),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
RaisedButton(
child: Text('Meeting Time'),
onPressed: () {
DatePicker.showTimePicker(context,
theme: DatePickerTheme(
containerHeight: 210.0,
),
showTitleActions: true, onConfirm: (time) {
print('confirm $time');
_time =
'${time.hour} : ${time.minute} : ${time.second}';
setState(() {});
},
currentTime: DateTime.now(),
locale: LocaleType.en);
setState(() {});
}),
Text(_time)
],
),
),
Padding(
padding: const EdgeInsets.only(top: 8.0, bottom: 8),
child: TextField(
controller: agendaController,
maxLines: null,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Agenda',
prefixIcon: Icon(Icons.message),
labelStyle: TextStyle(fontSize: 15)),
),
),
],
),
),
),
actions: <Widget>[
FlatButton(
child: Text("Save"),
onPressed: () {
// if (agendaController.text.isEmpty) return;
// if (_events[_controller.selectedDay] != null) {
// _events[_controller.selectedDay]
// .add(agendaController.text);
String asd = _controller.selectedDay.toString();
meetDate = asd.split(' ');
addMeetingToDatabase(meetDate);
agendaController.clear();
phoneController.clear();
locationController.clear();
Navigator.pop(context);
},
)
],
);
}
}
what i have achieved?
What i want to achieve
Instead of List<Dynamic>, it's better to map those data on an object so it can be accessed with a constant getter function.
Let Map<DateTime, List<dynamic>> _events; be Map<DateTime, EventDetails> _events;
where EventDetails contains for example:
class EventDetails {
String author;
String eventName;
String description;
EventDetails(
{required this.author,
required this.eventName,
required this.description});
}
Then you can add data using an Object.
EventDetails eventDetails = EventDetails(author: 'AUTHOR',
eventName: 'EVENT_NAME', description: 'DESCRIPTION');
...
_events[mee.dateTime].add(eventDetails);