Showing json data upon selecting item from suggestion list - flutter

I want to fetch and show corresponding player's data when their name is selected from the suggestion list. I have AutoCompleteTextField widget using which player's name is typed and selected from the list, as below:
Current issue I am facing is, when player is searched and selected, then I get null value back at first, as below:
But when I tap in the search field and select the same player again from suggestion list, then the api call is made and data is shown properly, as below:
Current code is, on itemSubmitted parameter of AutoCompleteTextfield, I am making call to the method that shows the data inside setState(), as below:
itemSubmitted: (item) {
setState(() {
searchTextField.textField.controller.text = item.name;
textInput = true;
showData();
});
},
Inside showData(), I am parsing the json per input search in the field and if player data is found, I am making another call inside same method to fetch the data, as below:
showData() {
String input = searchTextField.textField.controller.text.toLowerCase();
found = false;
for (var i = 0; i < PlayerViewModel.players.length; i++) {
if (PlayerViewModel.players[i].name.toLowerCase() == input) {
players = PlayerViewModel.players[i];
found = true;
break;
}
}
if (found) {
fetchJson(players.pid);
}
}
void fetchJson(int pid) async {
var response = await http.get(
'http://cricapi.com/api/playerStats?apikey=<apiKey>&pid=$pid');
if (response.statusCode == 200) {
String responseBody = response.body;
var responseJson = jsonDecode(responseBody);
name = responseJson['name'];
playingRole = responseJson['playingRole'];
battingStyle = responseJson['battingStyle'];
country = responseJson['country'];
imageURL = responseJson['imageURL'];
data = responseJson;
The data is fetched properly but not firing at first attempt when I select player from list, but only at second attempt when I select the player again from the list. And this happens for every subsequent player search.
What am I missing here ? How to fetch and show the data as soon as the player name is selected from suggestion list ?

You should implement a FutureBuilder where the future is fetchJson() which returns data. Also try to see what it returns.
if (found) {
fetchJson(players.pid).then(print);
}

Related

Flutter - loop not working while parsing json

I am trying to create model and parse json data from api
for that i created the model class you can see below
class FeatureModel {
String? PlanFeatures;
bool? FeatureStatus;
FeatureModel({this.PlanFeatures, this.FeatureStatus});
FeatureModel.fromJson(parsonJson) {
PlanFeatures = parsonJson['PlanFeatures'];
FeatureStatus = parsonJson['FeatureStatus'];
}
}
now i am trying to parse json with the help of loop
let me show you my method
List<FeatureModel> featureModel = [];
Uri featureAPI = Uri.parse(
planFeatureApi);
apiCall() async {
try {
http.Response response = await http.get(featureAPI);
// print(response.statusCode);
if (response.statusCode == 200) {
var decode = json.decode(response.body);
print(decode);
for (var i = 0; i < decode.length; i++) {
print(i);
featureModel.add(
FeatureModel.fromJson(decode[i]),
);
}
}
} catch (e) {}
}
I am calling it here
onPressed: () async{
await apiCall();
}
but the problem is here
loop is not working while parsing data
in that particular code i remains on 0 only
when i removes featureModel.add( FeatureModel.fromJson(decode[i]), ); i started increaing till 10
please let me know if i am making any mistake or what
thanks in advance
Here is the sample of api respone
[{"PlanFeatures":"Video Link Sharing","FeatureStatus":"true"},{"PlanFeatures":"Email \u0026amp; Telephonic Support","FeatureStatus":"true"},{"PlanFeatures":"Remove Pixeshare Branding","FeatureStatus":"false"},{"PlanFeatures":"Add Custom logo on uploaded photos","FeatureStatus":"false"},{"PlanFeatures":"Get Visitor Info","FeatureStatus":"false"},{"PlanFeatures":"Mobile Apps","FeatureStatus":"false"},{"PlanFeatures":"Send Questionnaries","FeatureStatus":"false"},{"PlanFeatures":"Create \u0026amp; Send Quotation","FeatureStatus":"false"},{"PlanFeatures":"Online Digital Album Sharing","FeatureStatus":"false"},{"PlanFeatures":"Analytics","FeatureStatus":"false"}]
thanks
I found many errors, first, the fromJson is not a factory constructor and doesn't return a class instance from the JSON.
the second one is that the bool values from the sample you added are String not a bool so we need to check over it.
try changing your model class to this:
class FeatureModel {
String? PlanFeatures;
bool? FeatureStatus;
FeatureModel({this.PlanFeatures, this.FeatureStatus});
factory FeatureModel.fromJson(parsonJson) {
return FeatureModel(
PlanFeatures: parsonJson['PlanFeatures'],
FeatureStatus: parsonJson['FeatureStatus'] == "false" ? false : true,
);
}
}

Remove column name after get data

So when I get some string data from database I'm using this method
var res = "";
Future<void> cetak(String query) async {
var req = await SqlConn.readData(query);
setState(() {
res = req;
});
}
then im using method cetak() like this
cetak("SELECT CUST_NAME FROM ts_custxm WHERE CUST_CODE = '$custCode'");
But when im trying to display the res using Text(res)
it show [{"CUST_NAME":"MY NAME"}]
any idea how to make res only show MY NAME without show its column name?
You first need to convert by jsonDecode() or json.decode():
var req = jsonDecode(req)
setState(() {
res = req;
});
and then access to your data by:
res[0]["CUST_NAME"].toString()
You are getting result of a query in res variable. As a result of a query is an array of objects.
in your case : [{"CUST_NAME":"MY NAME"}]
so get MY NAME you should use res[0]["CUST_NAME"].toString().
Hope this will help!

Is this approach is an Anti-Pattern? - Flutter

strong textI'm implementing a contacts list search bar, where the user can search & select some contacts, but I need the selected contacts to be shown as selected while the user is still searching.
I achieved this by modifying the original list and the duplicate list which used in the searching process at the same time.
is this an Anti-Pattern and is there a better way to do it?
Here's what I'm doing with the search query:
void searchContacts([String? name]) {
if (name == null || name.isEmpty) {
searchedList.clear();
addAllContactsToSearchList();
return;
} else {
searchedList.clear();
originalContactsList!.forEach((contact) {
if (contact.name.toLowerCase().contains(name.toLowerCase())) {
searchedList.clear();
searchedList.add(contact);
return;
} else {
return;
}
});
return;
}
}
and here's the code for selecting a contact:
void _onChange(bool value, int index) {
final selectedContact = searchedList[index].copyWith(isSelected: value);
searchedList.removeAt(index);
setState(() {
searchedList.insert(index, selectedContact);
notifier.originalContactsList = notifier.originalContactsList!.map((e) {
if (e.number == selectedContact.number) {
return selectedContact;
} else {
return e;
}
}).toList();
});}
This is expected behavior: gif
Some assumptions I'm making is that (1) each contact has a unique identifier that isn't just a name, and (2) you don't need the selected contacts to be shown in the same list as a search with a different query (if you search H, select Hasan, then search Ha, you expect it to still show up as selected on the next page, but if you search He, Hasan shouldn't shouldn't be on that next list.
The best way to do this is to have one constant list, and one list with results:
Set<String> selectedContactIds = {};
List<Contact> searchedList = [];
void _onChange(bool value, int index) {
final clickedContact = searchedList[index];
bool itemAlreadySelected = selectedContactIds.contains(clickedContact.userID);
setState({
if(itemAlreadySelected) {
selectedContactIds.remove(clickedContact.userID);
} else {
selectedContactIds.add(clickedContact.userID);
}
});
}
Now once you set state, your ListView should be updating the appearance of selected objects by checking if it's selected the same way that the _onChange function is checking if the item was already selected, which was:
bool itemAlreadySelected = selectedContactIds.contains(clickedContact.userID);
And this way, you don't have a whole class for contacts with a dedicated isSelected member. You wouldn't want that anyways because you're only selecting contacts for very specific case by case uses. Hopefully this helps!

How to use a variable for method name

I want to use a variable to access a certain value in my hive database:
In the code below if I use myBox.getAt(i).attributeSelect I get an error because attributeSelect is not defined for the box.
If I use myBox.getAt(i).test it works. How can I make flutter recognise that attributeSelect is a variable and put the value there? I have a total of 181 different variables the user can choose from. Do I really need that many if clauses? The variables are booleans. So I want to check if that attribute is true for the document at index i.
Error: NoSuchMethodError: 'attributeSelect'
method not found
Receiver: Instance of 'HiveDocMod'
attributeSelect = 'test'; //value depends on user choice
Future<void> queryHiveDocs() async {
final myBox = await Hive.openBox('my');
for (var i = 0; i < myBox.length; i++) {
if (attributeSelect == 'All Documents') {
_hiveDocs.add(myBox.getAt(i)); // get all documents
//print(myBox.getAt(24).vesselId);
} else {
// Query for attribute
if (myBox.getAt(i).attributeSelect) {
_hiveDocs.add(myBox.getAt(i)); // get only docs where the attributeSelect is true
}
}
}
setState(() {
_hiveDocs = _hiveDocs;
_isLoading = false;
});
}
I solved it the annoyingly hard way:
if (attributeSelect == 'crsAirCompressor') {
if (myBox.getAt(i).crsAirCompressor) {
_hiveDocs.add(myBox.getAt(i));
}
} else if (attributeSelect == 'crsBatteries') {
if (myBox.getAt(i).crsBatteries) {
_hiveDocs.add(myBox.getAt(i));
}...

Flutter Firestore Pagination (add/remove items)

I'm struggling to get this done, after two days I decided to ask you guys for help.
I'm using Mobx as state management, the issue is related to adding/removing an item to/from the list, e.g. if I retrieve two queries of 5 items each, according to the limit and then remove an item from the first query the first item from the second query is duplicate and if I add a new item, the first item from the second query is hidden. I have also set a scrollListener to the ListView.builder to get the bottom of the list and call for more items.
Thanks in advance,
#override
Stream<QuerySnapshot> teste(DocumentSnapshot lastDoc) {
if (lastDoc == null) {
return firestore.collection('teste')
.orderBy('name')
.limit(5)
.snapshots();
} else {
return firestore.collection('teste')
.orderBy('name')
.limit(5)
.startAfterDocument(lastDoc)
.snapshots();
}
}
#observable
ObservableList<List<TesteModel>> allPagedResults = ObservableList<List<TesteModel>>();
#observable
ObservableList<TesteModel> listTeste = ObservableList<TesteModel>();
#observable
DocumentSnapshot lastDoc;
#observable
bool hasMoreItem;
#action
void teste() {
var _currentRequestIndex = allPagedResults.length;
primaryRepository.teste(lastDoc).listen((query) {
if (query.docs.isNotEmpty) {
var _query = query.docs.map((doc) => TesteModel.fromFirestore(doc))
.toList();
var _pageExists = _currentRequestIndex < allPagedResults.length;
if (_pageExists) allPagedResults[_currentRequestIndex] = _query;
else allPagedResults.add(_query);
listTeste = allPagedResults.fold<List<TesteModel>>(<TesteModel>[],
(initialValue, pageItems) => initialValue..addAll(pageItems)).asObservable();
if (_currentRequestIndex == allPagedResults.length - 1) lastDoc = query.docs.last;
hasMoreItem = _query.length == 5;
}
});
}
Any luck with this issue?
For adding new items and having multiple pages you could do something like this:
if (allPagedResults.contains(allPagedResults[0].last) == false) {
allPagedResults.last.add(allPagedResults[0].last);
allPagedResults.last.remove(allPagedResults[0].first);
}