This is my model;
/*
// To parse this JSON data, do
//
// final hisselist = hisselistFromJson(jsonString);
import 'dart:convert';
Hisselist hisselistFromJson(String str) => Hisselist.fromJson(json.decode(str));
String hisselistToJson(Hisselist data) => json.encode(data.toJson());
class Hisselist {
Hisselist({
required this.success,
required this.result,
});
bool success;
List<ResultClass> result;
factory Hisselist.fromJson(Map<String, dynamic> json) => Hisselist(
success: json["success"], result: json["result"].map<ResultClass>((x) => ResultClass.fromJson(x)).toList(),
);
Map<String, dynamic> toJson() => {
"success": success,
"result": result.map((x) => x.toJson()),
};
}
class ResultClass {
ResultClass({
required this.rate,
required this.lastprice,
required this.lastpricestr,
required this.hacim,
required this.hacimstr,
required this.text,
required this.code,
});
double rate;
double lastprice;
String lastpricestr;
double hacim;
String hacimstr;
String text;
String code;
factory ResultClass.fromJson(Map<String, dynamic> json) => ResultClass(
rate: double.tryParse(json["rate"].toString()) ?? 0.0,
lastprice: double.tryParse(json["lastprice"].toString()) ?? 0.0,
lastpricestr: json["lastpricestr"],
hacim: double.tryParse(json["hacim"].toString()) ?? 0.0,
hacimstr: json["hacimstr"],
text: json["text"],
code: json["code"],
);
Map<String, dynamic> toJson() => {
"rate": rate,
"lastprice": lastprice,
"lastpricestr": lastpricestr,
"hacim": hacim,
"hacimstr": hacimstr,
"text": text,
"code": code,
};
}
*/
// To parse this JSON data, do
//
// final hisselist = hisselistFromJson(jsonString);
import 'dart:convert';
Hisselist hisselistFromJson(String str) => Hisselist.fromJson(json.decode(str));
String hisselistToJson(Hisselist data) => json.encode(data.toJson());
class Hisselist {
Hisselist({
required this.success,
required this.result,
});
bool success;
List<Result> result;
factory Hisselist.fromJson(Map<String, dynamic> json) => Hisselist(
success: json["success"],
result: List<Result>.from(json["result"].map((x) => Result.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"success": success,
"result": List<dynamic>.from(result.map((x) => x.toJson())),
};
}
class Result {
Result({
this.rate,
this.lastprice,
this.lastpricestr,
this.hacim,
this.hacimstr,
this.min,
this.minstr,
this.max,
this.maxstr,
this.time,
this.text,
this.code,
});
double? rate;
double? lastprice;
String? lastpricestr;
String? hacim;
String? hacimstr;
dynamic min;
String? minstr;
dynamic max;
String? maxstr;
Time? time;
String? text;
String? code;
factory Result.fromJson(Map<String, dynamic> json) => Result(
rate: json["rate"].toDouble(),
lastprice: json["lastprice"].toDouble(),
lastpricestr: json["lastpricestr"],
hacim: json["hacim"],
hacimstr: json["hacimstr"],
min: json["min"],
minstr: json["minstr"],
max: json["max"],
maxstr: json["maxstr"],
time: timeValues.map[json["time"]],
text: json["text"],
code: json["code"],
);
Map<String, dynamic> toJson() => {
"rate": rate,
"lastprice": lastprice,
"lastpricestr": lastpricestr,
"hacim": hacim,
"hacimstr": hacimstr,
"min": min,
"minstr": minstr,
"max": max,
"maxstr": maxstr,
"time": timeValues.reverse[time],
"text": text,
"code": code,
};
}
enum Time { THE_1809, THE_1808, THE_1805, THE_1810, THE_1759, THE_1755 }
final timeValues = EnumValues({
"17:55": Time.THE_1755,
"17:59": Time.THE_1759,
"18:05": Time.THE_1805,
"18:08": Time.THE_1808,
"18:09": Time.THE_1809,
"18:10": Time.THE_1810
});
class EnumValues<T> {
Map<String, T> map;
Map<T, String>? reverseMap;
EnumValues(this.map);
Map<T, String> get reverse {
if (reverseMap == null) {
reverseMap = map.map((k, v) => new MapEntry(v, k));
}
return reverseMap!;
}
}
This is where i call api:
class Hisseler extends StatefulWidget {
const Hisseler({Key? key}) : super(key: key);
@override
State<Hisseler> createState() => _HisselerState();
}
class _HisselerState extends State<Hisseler> {
final controller = TextEditingController();
final scaffoldKey = GlobalKey<ScaffoldState>();
final url = Uri.parse('https://api.collectapi.com/economy/hisseSenedi');
var counter;
Hisselist? hisseResult;
Future callHisse() async {
try{
Map<String, String> requestHeaders = {
'Content-Type': 'application/json',
'Authorization': 'apikey xxx:xxx'
};
final response = await http.get(url,headers:requestHeaders);
if(response.statusCode == 200){
var result = hisselistFromJson(response.body);
if(mounted);
setState(() {
counter = result.result.length;
result.result.sort((a, b) => (a.text ?? "").compareTo(b.text ?? ""));
hisseResult = result;
});
return result;
} else {
print(response.statusCode);
}
} catch(e) {
print(e.toString());
}
}
@override
void initState() {
// TODO: implement initState
super.initState();
callHisse();
}
@override
Widget build(BuildContext context) {
final style = controller.text.isEmpty
? const TextStyle(color: Colors.black54)
: const TextStyle(color: Colors.black);
return Scaffold(
appBar: AppBar(
centerTitle: false,
automaticallyImplyLeading: false,
title: Text(
'Hisseler'
),
),
body: Column(
children: [
Container(
margin: const EdgeInsets.fromLTRB(16, 16, 16, 16),
child: TextField(
controller: controller,
decoration: InputDecoration(
prefixIcon: const Icon(Icons.search),
suffixIcon: controller.text.isNotEmpty
? GestureDetector(
child: Icon(Icons.close, color: style.color),
onTap: () {
controller.clear();
FocusScope.of(context).requestFocus(FocusNode());
searchHisse('');
},
)
: null,
hintText: 'Hisse Ara',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(20),
borderSide: const BorderSide(color: Colors.black26),
),
),
onChanged: searchHisse,
),
),
Expanded(
child: Center(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: counter != null ?
ReorderableListView.builder(
itemCount: counter,
itemBuilder: (context, index){
return Card(
key: ValueKey(hisseResult?.result[index]),
child: ListTile(
contentPadding: EdgeInsets.all(10),
title: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text((hisseResult?.result[index].code ?? "")
.replaceAll("https:", ""),
style: TextStyle(
color: Colors.black,
fontSize: 16,
fontWeight: FontWeight.w500)),
Text(hisseResult?.result[index].text??"",style: TextStyle(color: Colors.grey[500], fontSize: 14))
],
),
trailing: Column(
children: <Widget>[
Text(hisseResult?.result[index].lastpricestr??"", style: TextStyle(color: Colors.black, fontSize: 16, fontWeight: FontWeight.w500)),
Container(
alignment: Alignment.center,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: (hisseResult?.result[index].rate ?? 0) > 0
? Colors.green
: Colors.red),
width: 75,
height: 25,
child: Text(hisseResult?.result[index].rate.toString() ?? "",
style: TextStyle(color: Colors.white)))
],
),
onTap: () => Navigator.push(
context, MaterialPageRoute(builder: (context) => StocksDetailScreen(
degisimoran: hisseResult?.result[index].rate!.toDouble(),
sondeger: hisseResult?.result[index].lastpricestr??"",
hacim: hisseResult?.result[index].hacimstr ?? "",
mindeger : hisseResult?.result[index].minstr?? "",
maxdeger : hisseResult?.result[index].maxstr?? "",
hisseismi : hisseResult?.result[index].text?? "",
hissekodu : hisseResult?.result[index].code?? "",
min : hisseResult?.result[index].min!.toDouble(),
max : hisseResult?.result[index].max!.toDouble(),
son : hisseResult?.result[index].lastprice!.toDouble(),
)),),
),
);
},
onReorder: (oldIndex, newIndex) {
setState(() {
if (newIndex > oldIndex) {
newIndex = newIndex - 1;
}
final element = hisseResult?.result.removeAt(oldIndex);
hisseResult?.result.insert(newIndex, element!);
});
},) : Center(child: CircularProgressIndicator(
)),
),
),
),
],
),
);
}
void searchHisse(String query) {
final suggestions = hisseResult?.result.where((code) {
final hisseTitle = hisseResult?.result;
final input = query.toLowerCase();
return hisseTitle!.contains(input);
}).toList();
setState(() => hisseResult = suggestions as Hisselist?);
}
}
But nothing happens on search result :
I think the problem is on searchHisse() but i am not sure. How can i make this work? Thanks for your help
CodePudding user response:
Based on your code , you only call api once and you get the full list only once too.
i think you need to separated in to 2 list object.
eg case:
initstate
you fetch apicallHisse();
and get the data.- then you can show all the data from
hisseResult
. - after 1 onchanged on
Textfield
you callsearchHisse(String query)
, which is updated yourhisseResult
. now you only have data with first letters from onchanged - then you tapped on textfield and clear the controller. there is no data on the list left that match to query
this is what i suggest
Hisselist? hisseResult; // data you get from API
Hisselist? hisseShow; // list that you show
and on your search function you need to add this condition
void searchHisse(String query) {
if (query == '') {
setState((){hisseShow =hisseResult;});
return;
}
final suggestions = hisseResult?.result.where((code) {
final hisseTitle = hisseResult?.result;
final input = query.toLowerCase();
return hisseTitle!.contains(input);
}).toList();
// based on your model data
setState(() => hisseShow = Hisselist(result: suggestions, success:true );
}
}
and you show your list
return Card(
key: ValueKey(hisseShow?.result[index]),
child: ListTile(
.....