Related
i have a chatting application and i want to do a search function where the user can enter into a textfield another users username and to show the searched users username and name so the user can message them,
the problem i have is that when i retrieved from my firebase the user with the same username entered it returned a Future<dynamic> instance which then results in an error in using docs: "The getter 'docs' isn't defined for the type 'Future<dynamic>' "
here is my code
class _search extends State<search> {
TextEditingController searchController = new TextEditingController();
late Future<dynamic> searchResult;
bool haveUserSearched =false;
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("search for user"),
centerTitle: true,
),
body: Container(
child: Column(
children: [
Container(
color: Color(0xfffffefa),
padding: EdgeInsets.symmetric(horizontal: 24, vertical: 16),
child: Row(
children: [
// GestureDetector(
// onTap: (){
// print(getUserByUsername(searchController.text));
// },
// child:
Expanded(child: TextField(
controller: searchController,
style: TextStyle(color: Color(0xffBFBBB7)),
onSubmitted: (value){
print(getUserByUsername(searchController.text));
},
decoration: InputDecoration(
hintText: "search by username",
hintStyle: TextStyle(color: Color(0xffBFBBB7)),
border: InputBorder.none,
prefixIcon: Icon(Icons.search,color: Color(0xffBFBBB7),),
),
),
),
//),
],
),
),
],
),
),
);
}
//-------methods and widgets-------
getUserByUsername(String username) async {
return await FirebaseFirestore.instance.collection('users').where('name',isEqualTo: username).get();
}
Widget userTile(String name,String username){
return Container(
padding: EdgeInsets.symmetric(horizontal: 24, vertical: 16),
child: Row(
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
name,
style: TextStyle(
color: Colors.white,
fontSize: 16
),
),
Text(
username,
style: TextStyle(
color: Colors.white,
fontSize: 16
),
)
],
),
Spacer(),
GestureDetector(
onTap: (){
//sendMessage(userName);
},
child: Container(
padding: EdgeInsets.symmetric(horizontal: 12,vertical: 8),
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(24)
),
child: Text("Message",
style: TextStyle(
color: Colors.white,
fontSize: 16
),),
),
)
],
),
);
}
Widget userList(){
return haveUserSearched ? ListView.builder(
shrinkWrap: true,
itemCount: 1, ///?
itemBuilder: (context, index){
return userTile(
searchResult.docs[index].data['name'], //the error here is in docs "The getter 'docs' isn't defined for the type 'Future<dynamic>' "
searchResult.docs[index].data["username"],
);
}) : Container();
}
}
searchResult is a Future, a representation of an eventual result (or error) from an asynchronous operation. You need to wait for the result, which you can do in various ways, such as await or FutureBuilder. In this circumstance, you may opt to choose the latter.
Please see Asynchronous programming: futures, async, await for more.
Use futureBuilder inside Column and pass fetched data like Widget userList(users) {
It can be like
class _search extends State<search> {
TextEditingController searchController = new TextEditingController();
bool haveUserSearched = false;
late Future<dynamic> searchResult = getUserByUsername(searchController.text);
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("search for user"),
centerTitle: true,
),
body: Container(
child: Column(
children: [
Container(
color: Color(0xfffffefa),
padding: EdgeInsets.symmetric(horizontal: 24, vertical: 16),
child: Row(
children: [
Expanded(
child: TextField(
controller: searchController,
style: TextStyle(color: Color(0xffBFBBB7)),
onSubmitted: (value) {
searchResult = getUserByUsername(searchController.text);
setState(() {});
},
decoration: InputDecoration(
hintText: "search by username",
hintStyle: TextStyle(color: Color(0xffBFBBB7)),
border: InputBorder.none,
prefixIcon: Icon(
Icons.search,
color: Color(0xffBFBBB7),
),
),
),
),
],
),
),
FutureBuilder(
future: searchResult,
builder: (context, snapshot) {
if (snapshot.hasData) {
return userList(snapshot.data);
}
return Text("handle other state");
},
),
],
),
),
);
}
//-------methods and widgets-------
getUserByUsername(String username) async {
final result = await FirebaseFirestore.instance
.collection('users')
.where('name', isEqualTo: username)
.get();
User myUser = User(name: result['name'] .....) //get user from Map.. it cant be..
return myUser;
}
Widget userTile(String name, String username) {
return Container(
padding: EdgeInsets.symmetric(horizontal: 24, vertical: 16),
child: Row(
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
name,
style: TextStyle(color: Colors.white, fontSize: 16),
),
Text(
username,
style: TextStyle(color: Colors.white, fontSize: 16),
)
],
),
Spacer(),
GestureDetector(
onTap: () {
//sendMessage(userName);
},
child: Container(
padding: EdgeInsets.symmetric(horizontal: 12, vertical: 8),
decoration: BoxDecoration(
color: Colors.blue, borderRadius: BorderRadius.circular(24)),
child: Text(
"Message",
style: TextStyle(color: Colors.white, fontSize: 16),
),
),
)
],
),
);
}
Widget userList(user) {
return haveUserSearched
? userTile(
user.name,
user.username,
)
: Container();
}
}
I am trying to assign a delivery agent to the order of products with a dropdown containing a list of delivery agents. I am trying to get documentId and merging new field value to the documentId which already exists. But as a result, I a getting a duplicate document with the same documentId containing filed values which I want to merge. kindly help me to understand what I am doing wrong.
full code order_view.dart
import 'package:flutter/material.dart';
import 'package:loading_animation_widget/loading_animation_widget.dart';
import '../../services/firebase_database.dart';
import '../widgets/snack_bar.dart';
import 'client_address.dart';
import 'dashboard.dart';
import 'package:url_launcher/url_launcher.dart';
class OrderView extends StatefulWidget {
final Map<String, dynamic> orderData;
final List<String> deliveryAgent;
const OrderView(
{Key? key, required this.orderData, required this.deliveryAgent})
: super(key: key);
#override
State<OrderView> createState() => _OrderViewState();
}
class _OrderViewState extends State<OrderView> {
final FirebaseDatabase _database = FirebaseDatabase();
int index = 0;
num totalAmount = 0;
Map<String, dynamic> clientData = {};
getcountTotalAmount() async {
for (var item in widget.orderData["orders"]) {
totalAmount = totalAmount + (item["productPrice"] * item["amount"]);
}
clientData = (await _database.getClientData(widget.orderData["userId"]))!;
setState(() {});
}
#override
void initState() {
getcountTotalAmount();
super.initState();
}
#override
Widget build(BuildContext context) {
bool _isloading = true;
return Scaffold(
backgroundColor: Colors.grey[200],
appBar: AppBar(
elevation: 4,
title: const Text("Open Order"),
actions: [
TextButton(
onPressed: () async {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
content: const Text(
"Are you sure you want to cancel this order?",
textAlign: TextAlign.center,
),
actions: [
TextButton(
onPressed: () {
Navigator.pop(context);
},
child: const Text(
"No",
style:
TextStyle(color: Colors.green, fontSize: 16),
)),
TextButton(
onPressed: () async {
// Navigator.pop(context);
showDialog(
context: context,
builder: (context) {
return LoadingAnimationWidget.inkDrop(
color: Colors.orange,
size: 50,
);
});
await _database.removeOrder(
createTime: widget.orderData["createAt"],
);
Navigator.of(context).pop();
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(
builder: (context) =>
const AdminDashboard()),
ModalRoute.withName(''),
);
ScaffoldMessenger.of(context).showSnackBar(
snackBar(
message: "Your order is removed",
color: Colors.deepOrange),
);
},
child: const Text(
"Yes",
style: TextStyle(color: Colors.red, fontSize: 16),
)),
],
);
});
},
child: const Text(
"Cancel Order",
style: TextStyle(
color: Colors.red,
fontWeight: FontWeight.w500,
fontSize: 15,
),
),
),
],
),
body: SizedBox(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child: ListView(
physics: const BouncingScrollPhysics(),
children: [
Container(
color: Colors.white,
child: ListView.separated(
padding: const EdgeInsets.symmetric(vertical: 8),
shrinkWrap: true,
itemCount: widget.orderData["orders"].length,
physics: const BouncingScrollPhysics(),
itemBuilder: (context, index) {
return ListTile(
leading: Image.network(
widget.orderData["orders"][index]["productImage"],
),
title: Text(
widget.orderData["orders"][index]["productTitle"],
),
subtitle: SizedBox(
width: MediaQuery.of(context).size.width,
child: Row(
children: [
Text(
"₹ ${widget.orderData["orders"][index]["productPrice"]}",
style: const TextStyle(
color: Colors.green, fontSize: 12),
),
const Text(" - "),
Text(
widget.orderData["orders"][index]["productUnit"],
style: const TextStyle(fontSize: 12),
),
const Text(" x "),
Text(widget.orderData["orders"][index]["amount"]
.toString()),
const SizedBox(width: 5),
Text(
"Total ₹ ${widget.orderData["orders"][index]["productPrice"] * widget.orderData["orders"][index]["amount"]}",
style: const TextStyle(
color: Colors.green,
fontWeight: FontWeight.w600,
fontSize: 12,
),
),
],
),
),
);
},
separatorBuilder: (BuildContext context, int index) {
return const Divider();
},
),
),
Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 8),
color: Colors.white,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text('Delivery Slot'),
Text(
'${widget.orderData["deliverySlot"]}',
style: const TextStyle(
fontWeight: FontWeight.w500, fontSize: 16),
),
],
),
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
"Delivery charge: ₹${widget.orderData["taxes"]}",
),
Text(
"Total Price: ₹${totalAmount + widget.orderData["taxes"]}",
style: const TextStyle(
fontWeight: FontWeight.w500, fontSize: 16),
),
],
)
],
),
),
const SizedBox(height: 16),
Container(
width: MediaQuery.of(context).size.width,
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 8),
decoration: const BoxDecoration(
color: Colors.white,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text(
'Ordered on: ${widget.orderData["createAt"]}',
style: const TextStyle(
fontWeight: FontWeight.w600,
fontSize: 14,
),
),
Text(
'Delivery at ${widget.orderData["addressType"]}',
),
const SizedBox(
height: 16,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(
width: MediaQuery.of(context).size.width * 0.6,
child: Text(
'Address: ${widget.orderData["address"]}',
),
),
ElevatedButton(
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => ClientAddress(
lat: widget.orderData["latitude"],
lag: widget.orderData["longitude"],
)));
},
child: const Text('Open location'))
],
),
],
),
),
const SizedBox(
height: 16,
),
Container(
width: MediaQuery.of(context).size.width,
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 8),
color: Colors.white,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
"Client Details",
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: 17,
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(
child: Text(
clientData["username"] ?? "",
style: const TextStyle(
fontWeight: FontWeight.w500,
fontSize: 15,
),
),
),
SizedBox(
child: Text(
clientData["contact"] ?? "",
style: const TextStyle(
fontWeight: FontWeight.w500,
fontSize: 15,
),
),
),
ElevatedButton.icon(
onPressed: () async {
String telephoneNumber = clientData["contact"];
Uri telephoneUrl = Uri.parse("tel:$telephoneNumber");
if (await canLaunchUrl(telephoneUrl)) {
await launchUrl(telephoneUrl);
}
},
icon: const Icon(
Icons.call,
),
label: const Text('Call'),
)
],
),
],
),
),
const SizedBox(
height: 16,
),
Container(
width: MediaQuery.of(context).size.width,
color: Colors.white,
padding: const EdgeInsets.only(bottom: 8),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
const Text(
"Delivery Agent",
style: TextStyle(
fontWeight: FontWeight.w500,
fontSize: 16,
),
),
DropdownButton(
items: widget.deliveryAgent
.map(
(e) => DropdownMenuItem(
value: e,
child: Text(e),
),
)
.toList(),
onChanged: (val) {
setState(() {
index =
widget.deliveryAgent.indexOf(val.toString());
});
},
isExpanded: false,
hint: Text(
widget.deliveryAgent[index],
style: const TextStyle(
fontWeight: FontWeight.w600,
fontSize: 15,
),
),
),
],
),
ElevatedButton(
onPressed: () async {
bool results;
results = await _database.updateDeliveryAgent(
orderId: widget.orderData["orderId"],
deliveryAgent: widget.deliveryAgent[index].toString(),
);
if (results) {
setState(() {
_isloading = true;
});
ScaffoldMessenger.of(context).showSnackBar(
snackBar(
message: "Delivery agent assigned",
color: Colors.green,
),
);
} else {
ScaffoldMessenger.of(context).showSnackBar(
snackBar(
message: "Error",
color: Colors.red,
),
);
}
setState(() {
_isloading = true;
});
},
child: const Text('Assign Agent')),
],
)),
],
),
),
);
}
}
firebase_database.dart
CollectionReference<Map<String, dynamic>> testorders =
FirebaseFirestore.instance.collection('testorders');
Future<bool> updateDeliveryAgent(
{required String orderId, required String deliveryAgent}) async {
try {
testorders.doc(orderId).set({
"deliveryAgent": {
"agentName": deliveryAgent,
"agentContact": '',
},
}, SetOptions(merge: true));
return true;
} catch (e) {
if (kDebugMode) {
print("error while assigning delivery agent: $e");
}
}
return false;
}
order.dart
Container(
width: MediaQuery.of(context).size.width,
color: Colors.white,
padding: const EdgeInsets.only(bottom: 8),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
const Text(
"Delivery Agent",
style: TextStyle(
fontWeight: FontWeight.w500,
fontSize: 16,
),
),
DropdownButton(
items: widget.deliveryAgent
.map(
(e) => DropdownMenuItem(
value: e,
child: Text(e),
),
)
.toList(),
onChanged: (val) {
setState(() {
index =
widget.deliveryAgent.indexOf(val.toString());
});
},
isExpanded: false,
hint: Text(
widget.deliveryAgent[index],
style: const TextStyle(
fontWeight: FontWeight.w600,
fontSize: 15,
),
),
),
],
),
ElevatedButton(
onPressed: () async {
bool results;
results = await _database.updateDeliveryAgent(
orderId: widget.orderData["orderId"],
deliveryAgent: widget.deliveryAgent[index].toString(),
);
if (results) {
setState(() {
_isloading = true;
});
ScaffoldMessenger.of(context).showSnackBar(
snackBar(
message: "Delivery agent assigned",
color: Colors.green,
),
);
} else {
ScaffoldMessenger.of(context).showSnackBar(
snackBar(
message: "Error",
color: Colors.red,
),
);
}
setState(() {
_isloading = true;
});
},
child: const Text('Assign Agent')),
],
)),
You cannot update a document ID once it's been defined.
See the following answer on alternative steps you can take: https://stackoverflow.com/a/52117929/9063088
There is no way you can have duplicate document IDs inside the same collection. The screenshot shows two documents sharing the same ID but for sure one of them contains one or more white spaces at the end. So there are two situations, the orderId is correct and when you call set() it adds the document with a document ID that doesn't contains white spaces, while in the database there is already one present that contains white spaces, or vice versa. When it comes to document IDs, always call .trim() so it can remove the white spaces from the beginning and from the end.
I fixed this, the main reason was firstly when I created the document with .add() where firebase auto generate the document ID, the and later while merging data in the same document ID it was creating the duplicate document ID maybe with some whitespace in it which was not visible.
But to rectify I created the data with .set() by generating the document by my own and later while merging data uses the same document ID to merge new fields in the same document ID. and finally it worked.
I'm using a TextFormField to filter an array of lists using GridView to display the Items. Inside my TextFormField there I used onChanged: onSearchTextChanged, which filters through the array response from the Rest API I created which is in json. The filter works fine but I'm looking for a way around showing no result when the user inputs a filter that is not available inside the filter. Below is my code:
TextFormField is as below:
TextFormField(
controller: controller,
keyboardType: TextInputType.text,
onChanged: onSearchTextChanged,
decoration: InputDecoration(
border: InputBorder.none,
contentPadding: EdgeInsets.fromLTRB(20.0, 15.0, 20.0, 15.0),
prefixText: ' ',
hintText: "Search",
hintStyle: TextStyle(
color: Colors.grey,fontWeight: FontWeight.normal,
fontSize: 15,
fontFamily:
'Montserrat'),
prefixIcon: Container(
child:Icon(
Icons.search,
color: Colors.grey,
size: 20,
)),
suffixIcon: backClear==true?InkWell(
onTap: () {
controller.clear();
onSearchTextChanged(
'');
},
child: Container(
child:Icon(
Icons.backspace,
color: Colors.grey,
size: 12,
))): Container(
child:Icon(
Icons.view_list_rounded,
color: Colors.grey,
size: 15,
)),
labelStyle: new TextStyle(color: Colors.grey),
),
)
onSearchTextChanged is as below:
onSearchTextChanged(String text) async {
_searchResult.clear();
if (text.isEmpty) {
setState(() {
backClear=false;
});
return;
}
content.forEach((userDetail) {
if (userDetail.username.toLowerCase().contains(text) || userDetail.username.toString().contains(text) ||
userDetail.username.toUpperCase().contains(text)||userDetail.fullname.toLowerCase().contains(text) || userDetail.fullname.toString().contains(text) ||
userDetail.fullname.toUpperCase().contains(text)||userDetail.phone.toLowerCase().contains(text) || userDetail.phone.toString().contains(text) ||
userDetail.phone.toUpperCase().contains(text)||userDetail.email.toLowerCase().contains(text) || userDetail.email.toString().contains(text) ||
userDetail.email.toUpperCase().contains(text) ) {
_searchResult.add(userDetail);
}
});
setState(() {
backClear=true;
});
}
For instance if John is not part of the return array list for username, fullname then on the screen it should show a message that says not found.
My gridview is as below:
Container(
child: _searchResult.length != 0 ||
controller.text.isNotEmpty
?new GridView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: _searchResult == null ? 0 : _searchResult.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount:3),
itemBuilder: (BuildContext context, int index){
return Card(
elevation: 1,
semanticContainer: true,
child:InkWell(
onTap: () async {
},
child: Container(
padding: EdgeInsets.all(10),
child:Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: <Widget>[
Flexible(
child: Column(
children: <Widget>[
Stack(
alignment: Alignment.bottomCenter,
children: [
CircleAvatar(
radius: 30,
backgroundColor: Colors.white,
child: _searchResult[index].profile_img!=null?Container(
padding: EdgeInsets.all(0),
child:CircleAvatar(
radius: 40,
backgroundImage:NetworkImage(_searchResult[index].profile_img
,),
backgroundColor: Colors.white,
//
)):Container(
padding: EdgeInsets.all(0),
child:CircleAvatar(
radius: 40,
backgroundImage:AssetImage('assets/person_icon.png'),
backgroundColor: Colors.white,
//
)),
),
],),
Flexible(
child: Center(child: Text(_searchResult[index].username==null?"AppName":_searchResult[index].username,style: TextStyle(
color: colorBlack,
fontWeight: FontWeight.normal,
fontSize: 10,
fontFamily: 'Montserrat',
),))),
Flexible(
child: Container(
padding: EdgeInsets.only(left: 15,right: 15,top: 1,bottom: 1),
decoration: BoxDecoration(
color: colorBlue,borderRadius: BorderRadius.circular(3)),
child: Text( "Follow",
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 10,
fontFamily: 'Montserrat',
),
),
),)
],
),
),
]))));
;})
:GridView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: content == null ? 0 : content.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount:3),
itemBuilder: (BuildContext context, int index){
return Card(
elevation: 1,
semanticContainer: true,
child:InkWell(
onTap: () async {
},
child: Container(
padding: EdgeInsets.all(10),
child:Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: <Widget>[
Flexible(
child: Column(
children: <Widget>[
Stack(
alignment: Alignment.bottomCenter,
children: [
CircleAvatar(
radius: 30,
backgroundColor: Colors.white,
child: content[index].profile_img!=null?Container(
padding: EdgeInsets.all(0),
child:CircleAvatar(
radius: 40,
backgroundImage:NetworkImage(content[index].profile_img
,),
backgroundColor: Colors.white,
//
)):Container(
padding: EdgeInsets.all(0),
child:CircleAvatar(
radius: 40,
backgroundImage:AssetImage('assets/person_icon.png'),
backgroundColor: Colors.white,
//
)),
),
],),
Flexible(
child: Center(child: Text(content[index].username==null?"AppName":content[index].username,style: TextStyle(
color: colorBlack,
fontWeight: FontWeight.normal,
fontSize: 10,
fontFamily: 'Montserrat',
),))),
Flexible(
child: Container(
padding: EdgeInsets.only(left: 15,right: 15,top: 1,bottom: 1),
decoration: BoxDecoration(
color: colorBlue,borderRadius: BorderRadius.circular(3)),
child: Text( "Follow",
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 10,
fontFamily: 'Montserrat',
),
),
),)
],
),
),
]))));}))
I'm not sure on where you actually display results in your sample code, but the logic you could implement is the following.
After the forEach you should check if some result is actually found, and in case it wasn't, set a showNotFoundText to true so that in your view you can display the message.
onSearchTextChanged(String text) async {
_searchResult.clear();
if (text.isEmpty) {
setState(() {
backClear=false;
showNotFoundText = false;
});
return;
}
content.forEach((userDetail) {
if (userDetail.username.toLowerCase().contains(text) || userDetail.username.toString().contains(text) ||
userDetail.username.toUpperCase().contains(text)||userDetail.fullname.toLowerCase().contains(text) || userDetail.fullname.toString().contains(text) ||
userDetail.fullname.toUpperCase().contains(text)||userDetail.phone.toLowerCase().contains(text) || userDetail.phone.toString().contains(text) ||
userDetail.phone.toUpperCase().contains(text)||userDetail.email.toLowerCase().contains(text) || userDetail.email.toString().contains(text) ||
userDetail.email.toUpperCase().contains(text) ) {
_searchResult.add(userDetail);
}
});
if (_searchResult.isEmpty) {
//Do something
setState(() {
showNotFoundText = true;
});
}
setState(() {
backClear=true;
});
}
Add something like this in your view
showNotFoundText ? Text("No results found") : Container() //Empty container instead
Since you didn't include the code for the results display, I made it this way, but you may also consider using this logic directly in your view:
_searchResult.isEmpty ? Text("No results found") : DisplayResultsWidget()
With the suggestion of Dani3le_ to use add below if statement inside my onSearchTextChanged and I declare my bool showNotFoundText = false; above my code
if (_searchResult.isEmpty) {
//Do something
setState(() {
showNotFoundText = true;
});
}
and above my Gridview I added the below to show the No result message find below the code:
showNotFoundText==true ? Text("No result found!",style: TextStyle(fontFamily: 'Montserrat',color: Colors.grey, fontSize: 13, fontWeight: FontWeight.bold),) : Container(),
But onPress of backspace the No result found still shows even if the input is available on the search list so I add showNotFoundText = false; to setState() so that every time the backspace is pressd it set the state of showNotFoundText back to false as shown below:
setState(() {
showNotFoundText = false;
});
Hi in the below code when I enter my mobile number, password and then click on the login button nothing is happening. My API working in Postman is not working here.
When I press the button it is not working, Entering a valid mobile number and password are not working.
Can anyone help me to find where I did any mistakes?
Login_screen.dart:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:sample_live/home_screen.dart';
import 'package:sample_live/model/login_model.dart';
import 'package:sample_live/splash_screen.dart';
import 'package:sample_live/login_otp.dart';
import 'ProgressHUD.dart';
import 'api/api_service.dart';
class LoginScreen extends StatefulWidget {
String name;
LoginScreen({this.name});
#override
_LoginScreenState createState() => _LoginScreenState();
}
class _LoginScreenState extends State<LoginScreen> {
final mobileController = TextEditingController();
final passwordController = TextEditingController();
LoginRequestModel requestModel;
bool isApiCallProcess = false;
GlobalKey<FormState> globalFormKey = GlobalKey<FormState>();
LoginRequestModel loginRequestModel;
final scaffoldKey = GlobalKey<ScaffoldState>();
#override
void initState(){
super.initState();
requestModel=new LoginRequestModel();
}
#override
Widget build(BuildContext context) {
return ProgressHUD(
child: _uiSetup(context),
inAsyncCall: isApiCallProcess,
opacity: 0.3,
);
}
Widget _uiSetup(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Login", style: TextStyle(color: Colors.white)),
centerTitle: true,
),
body:
Stack(
children: [
Padding(
padding: EdgeInsets.all(30),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset('assets/images/hand.png',),
Padding(
padding: EdgeInsets.all(10),
child: Text("Welcome Doctor! ",
style: TextStyle(
color: Colors.black,
fontSize: 20,
fontWeight: FontWeight.bold
),),
),
Padding(
padding: EdgeInsets.all(10),
),
Text("Let's treat everyone great",
style: TextStyle(
color: Colors.black,
fontSize: 15,
),),
Padding(
padding: EdgeInsets.all(10),
),
TextFormField(
minLines: 1,
keyboardType: TextInputType.number,
onSaved: (input) => loginRequestModel.Mobile = input,
textInputAction: TextInputAction.next,
decoration: InputDecoration(
labelText: "Enter Mobile No.",
hintText: "Enter Mobile No.",
border: OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(16.0)))),
),
SizedBox(
height: 10,
),
TextFormField(
onSaved: (input) =>
loginRequestModel.Password = input,
validator: (input) =>
input.length < 3
? "Password should be more than 3 characters"
: null,
minLines: 1,
obscureText: true,
keyboardType: TextInputType.text,
textInputAction: TextInputAction.next,
decoration: InputDecoration(
labelText: "Password",
hintText: "Password",
border: OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(16.0)))),
),
SizedBox(
height: 10,
),
Container(
width: double.infinity,
padding: EdgeInsets.symmetric(vertical: 20, horizontal: 20),
margin: EdgeInsets.symmetric(vertical: 20, horizontal: 20),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30)
),
child: RaisedButton(
color: Color(0xFF0769AA),
onPressed: () {
if (validateAndSave()) {
print(loginRequestModel.toJson());
setState(() {
isApiCallProcess = true;
});
APIService apiService = new APIService();
apiService.login(loginRequestModel).then((value) {
if (value != null) {
setState(() {
isApiCallProcess = false;
});
if (value.Status.isNotEmpty) {
final snackBar = SnackBar(
content: Text("Login Successful"));
scaffoldKey.currentState
.showSnackBar(snackBar);
} else {
final snackBar =
SnackBar(content: Text(value.Message));
scaffoldKey.currentState
// ignore: deprecated_member_use
.showSnackBar(snackBar);
}
}
});
}
},
child: Text(
"Login",
style: TextStyle(color: Colors.white),
),
),
),
SizedBox(
height: 10,
),
Text("Or",
style: TextStyle(
color: Colors.black,
fontSize: 15,
),),
Container(
width: double.infinity,
child: FlatButton(
color: Color(0xFF0769AA),
onPressed: () {
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(
builder: (context) => LoginOtp("Welcome")),
(route) => false);
},
child: Text(
"Login With OTP",
style: TextStyle(color: Colors.white),
),
),
),
SizedBox(
height: 10,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
GestureDetector(
onTap: () {
// write your function
Navigator.push(
context,
MaterialPageRoute(
builder: (contex) => SplashScreen()));
},
child: Text(
"Forgot Password",
style: TextStyle(
color: Colors.blue,
fontSize: 16,
fontWeight: FontWeight.bold,
)
)),
],
),
],
),
),
Container(
alignment: Alignment.bottomCenter,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.end,
children: [
Text(
"By logging in or signing up, you agree to the",
textAlign: TextAlign.end,
style: TextStyle(
color: Colors.black,
fontSize: 12,
),
),
Text(
"Privacy Policy & Terms and Condition",
textAlign: TextAlign.end,
style: TextStyle(
color: Colors.blue,
fontSize: 12,
),
),
],
)
)
]),
);
}
bool validateAndSave() {
final form = globalFormKey.currentState;
if (form.validate()) {
form.save();
return true;
}
return false;
}
}
I created dropdown in TextFormField in flutter, i successfully loaded list (bankDataList) into dropdown which is dynamic list. Data is showing into dropdown list. But i have a problem to assign
"value : _bankChoose" into DropDownButton , it is not updating into TextFormField. I am using icon and text, please see screenshot.
String _bankChoose;
List<BankListDataModel> bankDataList;
Container(
margin: EdgeInsets.only(left: 15, top: 10, right: 15),
child: FormField<String>(
builder: (FormFieldState<String> state) {
return InputDecorator(
decoration: InputDecoration(
contentPadding:
EdgeInsets.fromLTRB(12, 10, 20, 20),
// labelText: "hi",
// labelStyle: textStyle,
// labelText: _dropdownValue == null
// ? 'Where are you from'
// : 'From',
errorText: _errorBank,
errorStyle: TextStyle(
color: Colors.redAccent, fontSize: 16.0),
border: OutlineInputBorder(
borderRadius:
BorderRadius.circular(10.0))),
child: DropdownButtonHideUnderline(
child: DropdownButton<BankListDataModel>(
style: TextStyle(
fontSize: 16,
color: text_gray_color,
fontFamily: "verdana_regular",
),
hint: Text(
"Select Bank",
style: TextStyle(
color: text_gray_color,
fontSize: 16,
fontFamily: "verdana_regular",
),
),
value: _bankChoose,
isExpanded: true,
isDense: true,
onChanged: (BankListDataModel newValue) {
setState(() {
_bankChoose = newValue.bank_name;
});
},
items: bankDataList
.map<DropdownMenuItem<BankListDataModel>>(
(BankListDataModel valueItem) {
return DropdownMenuItem(
value: valueItem,
child: Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
new CircleAvatar(
backgroundImage: new NetworkImage(
valueItem.bank_logo),
),
// Icon(valueItem.bank_logo),
SizedBox(
width: 15,
),
Text(valueItem.bank_name),
],
),
);
}).toList(),
),
),
);
},
),
),
You want to choose drop down item of type BankListDataModel, then your _bankChoose variable should be of type BankListDataModel.
Try this one,
import 'package:flutter/material.dart';
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
//String _bankChoose;
BankListDataModel _bankChoose;
List<BankListDataModel> bankDataList=[
BankListDataModel("SBI","https://www.kindpng.com/picc/m/83-837808_sbi-logo-state-bank-of-india-group-png.png"),
BankListDataModel("HDFC","https://www.pngix.com/pngfile/big/12-123534_download-hdfc-bank-hd-png-download.png"),
BankListDataModel("ICICI","https://www.searchpng.com/wp-content/uploads/2019/01/ICICI-Bank-PNG-Icon-715x715.png"),
//BankListDataModel("Canara","https://bankforms.org/wp-content/uploads/2019/10/Canara-Bank.png")
];
#override
void initState() {
super.initState();
_bankChoose = bankDataList[0];
}
void _onDropDownItemSelected(BankListDataModel newSelectedBank) {
setState(() {
_bankChoose = newSelectedBank;
});
}
#override
Widget build(BuildContext context) {
return
Scaffold(
body: Form(
child: Center(
child: Container(
margin: EdgeInsets.only(left: 15, top: 10, right: 15),
child: FormField<String>(
builder: (FormFieldState<String> state) {
return InputDecorator(
decoration: InputDecoration(
contentPadding:
EdgeInsets.fromLTRB(12, 10, 20, 20),
// labelText: "hi",
// labelStyle: textStyle,
// labelText: _dropdownValue == null
// ? 'Where are you from'
// : 'From',
errorText: "Wrong Choice",
errorStyle: TextStyle(
color: Colors.redAccent, fontSize: 16.0),
border: OutlineInputBorder(
borderRadius:
BorderRadius.circular(10.0))),
child: DropdownButtonHideUnderline(
child: DropdownButton<BankListDataModel>(
style: TextStyle(
fontSize: 16,
color: Colors.grey,
fontFamily: "verdana_regular",
),
hint: Text(
"Select Bank",
style: TextStyle(
color: Colors.grey,
fontSize: 16,
fontFamily: "verdana_regular",
),
),
items: bankDataList
.map<DropdownMenuItem<BankListDataModel>>(
(BankListDataModel value) {
return DropdownMenuItem(
value: value,
child: Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
new CircleAvatar(
backgroundImage: new NetworkImage(
value.bank_logo),
),
// Icon(valueItem.bank_logo),
SizedBox(
width: 15,
),
Text(value.bank_name),
],
),
);
}).toList(),
isExpanded: true,
isDense: true,
onChanged: (BankListDataModel newSelectedBank) {
_onDropDownItemSelected(newSelectedBank);
},
value: _bankChoose,
),
),
);
},
),
),
),
),
);
}
}
class BankListDataModel{
String bank_name;
String bank_logo;
BankListDataModel(this.bank_name,this.bank_logo);
}
sorry for formatting of images.
One way would be to use a TextEditingController and assign is to your TextField with controller: textEditingController for example
final textEditingController = TextEditingController();