How to implement a process that uses flutter_secure_storage package to read and write the data [with Provider package] - flutter

I'm new to Flutter and Dart. I made a simple Todos app with Provider package and Consumer. I'm trying to implement a process that uses flutter_secure_storage package to read and write the list data on the device.
But I don't know how to implement it.
Checkbox widget requires a bool, while secure_storage requires the type of String. Therefore, it is necessary to convert both types. This also confuses me a little.
The code is below.
I would be happy if you could give me some advice.
main.dart
// Todos app example
import 'package:consumer_samp/list_model.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: ChangeNotifierProvider<ListModel>(
create: (context) => ListModel(),
child: MyHomePage('Todos app example'),
),
);
}
}
class MyHomePage extends StatelessWidget {
MyHomePage(this.title);
final String title;
final TextEditingController eCtrl = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(title),
),
body: SingleChildScrollView(
child: Column(
children: <Widget>[
Container(
padding: EdgeInsets.all(10),
child: Row(
children: <Widget>[
Expanded(
child: TextField(
decoration: InputDecoration(
border: InputBorder.none,
hintText: 'Enter your ToDo item',
),
controller: eCtrl,
),
),
Consumer<ListModel>(
builder: (_, listModel, __) => FlatButton(
child: Text('Add'),
onPressed: () {
if (eCtrl.text != '') {
Map<String, dynamic> item = {
'value': false,
'text': eCtrl.text
};
listModel.addItem(item);
eCtrl.clear();
}
},
),
),
],
),
),
Center(
child: Consumer<ListModel>(builder: (_, listModel, __) {
var items = listModel.getItems;
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
height: 300,
child: ListView.builder(
itemCount: items.length,
itemBuilder: (BuildContext context, int idx) =>
Container(
padding: const EdgeInsets.all(5),
color: Colors.green,
child: Row(
children: <Widget>[
Checkbox(
value: items[idx]['value'],
onChanged: (val) {
listModel.toggleValue(idx, val);
}),
Text(
items[idx]['text'],
style: TextStyle(
fontSize: 21, color: Colors.white),
),
],
),
),
),
),
],
);
}),
),
],
),
),
);
}
}
list_model.dart
import 'package:flutter/cupertino.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
class ListModel with ChangeNotifier {
List<Map<String, dynamic>> _items = [];
List<Map<String, dynamic>> get getItems => _items;
void addItem(Map<String, dynamic> item) {
_items.add(item);
notifyListeners();
}
void toggleValue(int idx, bool val) {
_items[idx]['value'] = val;
notifyListeners();
}
}

You can copy paste run full code below
You can use class TodoItem and save/load with JSON String
Provider logic for secure storage is in full code, too long to describe detail
code snippet
List<TodoItem> todoItemFromJson(String str) =>
List<TodoItem>.from(json.decode(str).map((x) => TodoItem.fromJson(x)));
String todoItemToJson(List<TodoItem> data) =>
json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class TodoItem {
TodoItem({
this.item,
this.checked,
});
String item;
bool checked;
factory TodoItem.fromJson(Map<String, dynamic> json) => TodoItem(
item: json["item"],
checked: json["checked"],
);
Map<String, dynamic> toJson() => {
"item": item,
"checked": checked,
};
}
working demo
full code
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'dart:convert';
List<TodoItem> todoItemFromJson(String str) =>
List<TodoItem>.from(json.decode(str).map((x) => TodoItem.fromJson(x)));
String todoItemToJson(List<TodoItem> data) =>
json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class TodoItem {
TodoItem({
this.item,
this.checked,
});
String item;
bool checked;
factory TodoItem.fromJson(Map<String, dynamic> json) => TodoItem(
item: json["item"],
checked: json["checked"],
);
Map<String, dynamic> toJson() => {
"item": item,
"checked": checked,
};
}
class ListModel with ChangeNotifier {
FlutterSecureStorage _storage;
List<TodoItem> _items = [];
List<TodoItem> get getItems => _items;
initilaize() async {
print("initialize");
String jsonString = await _storage.read(key: "todo");
if (jsonString != null) {
_items = todoItemFromJson(jsonString);
notifyListeners();
}
}
ListModel.init(FlutterSecureStorage storage) {
print("init");
_storage = storage;
initilaize();
}
void update(FlutterSecureStorage storage) {
print("update");
_storage = storage;
}
void addItem(TodoItem item) {
_items.add(item);
notifyListeners();
}
void toggleValue(int idx, bool val) {
_items[idx].checked = val;
notifyListeners();
}
}
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: MultiProvider(
providers: [
Provider<FlutterSecureStorage>(create: (_) => FlutterSecureStorage()),
ChangeNotifierProxyProvider<FlutterSecureStorage, ListModel>(
create: (_) {
return ListModel.init(
Provider.of<FlutterSecureStorage>(_, listen: false));
},
update: (_, storage, listModel) => listModel..update(storage),
),
],
child: MyHomePage('Todos app example'),
),
);
}
}
class MyHomePage extends StatelessWidget {
MyHomePage(this.title);
final String title;
final TextEditingController eCtrl = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(title),
actions: <Widget>[
Consumer2<ListModel, FlutterSecureStorage>(
builder: (_, listModel, storage, __) => IconButton(
icon: Icon(Icons.save),
onPressed: () async {
await storage.write(
key: "todo", value: todoItemToJson(listModel._items));
print("save done");
},
))
],
),
body: SingleChildScrollView(
child: Column(
children: <Widget>[
Container(
padding: EdgeInsets.all(10),
child: Row(
children: <Widget>[
Expanded(
child: TextField(
decoration: InputDecoration(
border: InputBorder.none,
hintText: 'Enter your ToDo item',
),
controller: eCtrl,
),
),
Consumer<ListModel>(
builder: (_, listModel, __) => FlatButton(
child: Text('Add'),
onPressed: () {
if (eCtrl.text != '') {
Map<String, dynamic> item = {
'value': false,
'text': eCtrl.text
};
listModel.addItem(
TodoItem(item: eCtrl.text, checked: false));
eCtrl.clear();
}
},
),
),
],
),
),
Center(
child: Consumer<ListModel>(builder: (_, listModel, __) {
var items = listModel.getItems;
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
height: 300,
child: ListView.builder(
itemCount: items.length,
itemBuilder: (BuildContext context, int idx) =>
Container(
padding: const EdgeInsets.all(5),
color: Colors.green,
child: Row(
children: <Widget>[
Checkbox(
value: items[idx].checked,
onChanged: (val) {
listModel.toggleValue(idx, val);
}),
Text(
items[idx].item,
style: TextStyle(
fontSize: 21, color: Colors.white),
),
],
),
),
),
),
],
);
}),
),
],
),
),
);
}
}

As mentioned in the readme files by the following link
https://pub.dev/packages/flutter_secure_storage
The following code instantiate the storage, and the following code's must be in a async method as this returns a future.
final storage = new FlutterSecureStorage();
And you can pass the _items list as a value and you can set some key name
await storage.write(key: key, value: _items);
And then you could get that value by using the key name (which is set while storing)
List<Map<String, dynamic>> _value = await storage.read(key: key);
And then you could map the _value you get from storage and you can store it in _items. And then you could do various operations and queries inside your app now with all data you have.
Make a note! I haven't tried this approach in my code base. Just I said what I thought. Please try this in your code and comment me please.
The following code executes correctly use this in model, for storing data:
Future<void> _storingData() async {
final storage = new FlutterSecureStorage();
for (int i = 0; i < _items.length; i++) {
await storage
.write(key: _items[i]['text'], value: "${_items[i]['value']}")
.then((value) => print("success"));
}
}
For retrieving data:
Future<void> retrivingData() async {
final storage = new FlutterSecureStorage();
Map<String, String> allValues = await storage.readAll();
print(allValues);
allValues.forEach((key, value) {
bool val = bool.fromEnvironment(value, defaultValue: false);
Map<String, dynamic> item = {'value': val, 'text': key};
addItem(item);
});
}
and finally I stored all values again to a list.
You should do some changes in your code in main.dart according to the above methods based on your usage.

Related

Implementing Algolia Search in Flutter

I am trying to implement algolia search in flutter with filters.
I found an article on the algolia website which I followed to a tee to get to this stage in the implementation but I am getting this error and have no clue what to do about it:
lib/services/search.dart:194:52: Error: Member not found: 'fromResponse'.
_assetsSearcher.responses.map(SearchMetadata.fromResponse);
^^^^^^^^^^^^
lib/services/search.dart:200:46: Error: Member not found: 'fromResponse'.
_assetsSearcher.responses.map(HitsPage.fromResponse);
^^^^^^^^^^^^
This is my code:
class SearchMetadata {
final int nbHits;
const SearchMetadata(this.nbHits);
factory SearchMetadata.fromResponse(SearchResponse response) =>
SearchMetadata(response.nbHits);
}
class Asset {
final String code;
final String name;
final String desc;
final String loc;
final String img;
Asset(this.code, this.name, this.desc, this.loc, this.img);
static Asset fromJson(Map<String, dynamic> json) {
return Asset(
json['name'], json['desc'], json['desc'], json['loc'], json['img']);
}
}
class HitsPage {
const HitsPage(this.assets, this.pageKey, this.nextPageKey);
final List<Asset> assets;
final int pageKey;
final int? nextPageKey;
factory HitsPage.fromResponse(SearchResponse response) {
final assets = response.hits.map(Asset.fromJson).toList();
final isLastPage = response.page >= response.nbPages;
final nextPageKey = isLastPage ? null : response.page + 1;
return HitsPage(assets, response.page, nextPageKey);
}
}
class AlgoliaSearchFilters extends StatefulWidget {
const AlgoliaSearchFilters({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<AlgoliaSearchFilters> createState() => _AlgoliaSearchFiltersState();
}
class _AlgoliaSearchFiltersState extends State<AlgoliaSearchFilters> {
final _searchTextController = TextEditingController();
final _assetsSearcher = HitsSearcher(
applicationID: 'OPN6AROJK6',
apiKey: '0ba458475d25b7e2069d700c32e42f29',
indexName: 'asset');
Stream<SearchMetadata> get _searchMetadata =>
_assetsSearcher.responses.map(SearchMetadata.fromResponse);
final PagingController<int, Asset> _pagingController =
PagingController(firstPageKey: 0);
Stream<HitsPage> get _searchPage =>
_assetsSearcher.responses.map(HitsPage.fromResponse);
final GlobalKey<ScaffoldState> _mainScaffoldKey = GlobalKey();
final _filterState = FilterState();
late final _facetList = FacetList(
searcher: _assetsSearcher, filterState: _filterState, attribute: 'loc');
#override
void initState() {
super.initState();
_searchTextController
.addListener(() => _assetsSearcher.query(_searchTextController.text));
_searchPage.listen((page) {
if (page.pageKey == 0) {
_pagingController.refresh();
}
_pagingController.appendPage(page.assets, page.nextPageKey);
}).onError((error) => _pagingController.error = error);
_pagingController.addPageRequestListener((pageKey) =>
_assetsSearcher.applyState((state) => state.copyWith(page: pageKey)));
_assetsSearcher.connectFilterState(_filterState);
_filterState.filters.listen((_) => _pagingController.refresh());
}
#override
Widget build(BuildContext context) {
return Scaffold(
key: _mainScaffoldKey,
appBar: AppBar(
backgroundColor: Colors.blue[900],
title: const Text("Algolia Flutter Search"),
actions: [
IconButton(
onPressed: () => _mainScaffoldKey.currentState?.openEndDrawer(),
icon: const Icon(Icons.filter_list_sharp))
],
),
endDrawer: Drawer(
child: _filters(context),
),
body: Center(
child: Column(
children: <Widget>[
SizedBox(
height: 44,
child: TextField(
controller: _searchTextController,
decoration: const InputDecoration(
border: InputBorder.none,
hintText: 'Enter a search term',
prefixIcon: Icon(Icons.search),
),
)),
StreamBuilder<SearchMetadata>(
stream: _searchMetadata,
builder: (context, snapshot) {
if (!snapshot.hasData) {
return const SizedBox.shrink();
}
return Padding(
padding: const EdgeInsets.all(8.0),
child: Text('${snapshot.data!.nbHits} hits'),
);
},
),
Expanded(
child: _hits(context),
)
],
),
),
);
}
Widget _hits(BuildContext context) => PagedListView<int, Asset>(
pagingController: _pagingController,
builderDelegate: PagedChildBuilderDelegate<Asset>(
noItemsFoundIndicatorBuilder: (_) => const Center(
child: Text('No results found'),
),
itemBuilder: (_, item, __) => Container(
color: Colors.white,
height: 80,
padding: const EdgeInsets.all(8.0),
child: Row(
children: [
SizedBox(width: 50, child: Image.network(item.img)),
const SizedBox(width: 20),
Expanded(child: Text(item.name))
],
),
)));
Widget _filters(BuildContext context) => Scaffold(
appBar: AppBar(
backgroundColor: Colors.blue[900],
title: const Text('Filters'),
),
body: StreamBuilder<List<SelectableItem<Facet>>>(
stream: _facetList.facets,
builder: (context, snapshot) {
if (!snapshot.hasData) {
return const SizedBox.shrink();
}
final selectableFacets = snapshot.data!;
return ListView.builder(
padding: const EdgeInsets.all(8.0),
itemCount: selectableFacets.length,
itemBuilder: (_, index) {
final selectableFacet = selectableFacets[index];
return CheckboxListTile(
value: selectableFacet.isSelected,
title: Text(
'${selectableFacet.item.value} (${selectableFacet.item.count})'),
onChanged: (_) {
_facetList.toggle(selectableFacet.item.value);
},
);
});
}),
);
#override
void dispose() {
_searchTextController.dispose();
_assetsSearcher.dispose();
_pagingController.dispose();
_filterState.dispose();
_facetList.dispose();
super.dispose();
}
}
It shows up as an error only when I run my program
Please let me know of any fixes
Thanks!
I had the same issue after updating flutter. Try run
flutter pub upgrade
to upgrade all your dependencies as this is caused by a transitive dependencies.

Duplicate GlobalKey detected in tree widget scaffoldState

I was trying to update data (add, edit, delete) from my list using API, when I clicked something to update the list e.g deleting an item it showed a successfully updated. but in the Debug Console, there's an error that says
The following assertion was thrown while finalizing the widget tree:
Duplicate GlobalKey detected in the widget tree. The following GlobalKey
was specified multiple times in the widget tree. This will lead to
parts of the widget tree being truncated unexpectedly, because the
second time a key is seen, the previous instance is moved to the new
location. The key was:
[LabeledGlobalKey #47c37] This was determined by noticing that after the widget with the above global key was moved out
of its previous parent, that previous parent never updated during this
frame, meaning that it either did not update at all or updated before
the widget was moved, in either case implying that it still thinks
that it should have a child with that global key.
And when I tried going back to the Previous screen it just showed Blank Screen
Here's the code
Model
import 'dart:convert';
class Nasabah {
int id;
String nama_debitur;
String alamat;
String no_telp;
String no_ktp;
String no_selular;
Nasabah({
this.id = 0,
this.nama_debitur,
this.alamat,
this.no_telp,
this.no_ktp,
this.no_selular,
});
factory Nasabah.fromJson(Map<String, dynamic> json) => Nasabah(
id: json["id"],
nama_debitur: json["nama_debitur"],
alamat: json["alamat"],
no_telp: json["no_telp"],
no_ktp: json["no_ktp"],
no_selular: json["no_selular"],
);
factory Nasabah.fromMap(Map<String, dynamic> map) => Nasabah(
id: map["id"],
nama_debitur: map["nama_debitur"],
alamat: map["alamat"],
no_telp: map["no_telp"],
no_ktp: map["no_ktp"],
no_selular: map["no_selular"],
);
Map<String, dynamic> toJson() => {
"id": id,
"nama_debitur": nama_debitur,
"alamat": alamat,
"no_telp": no_telp,
"no_ktp": no_ktp,
"no_selular": no_selular,
};
#override
String toString() {
return 'Nasabah{id: $id, nama_debitur: $nama_debitur, alamat: $alamat, no_telp: $no_telp, no_ktp: $no_ktp, no_selular: $no_selular}';
}
}
class NasabahResult {
String status;
List<Nasabah> data = new List<Nasabah>();
NasabahResult({
this.status,
this.data,
});
factory NasabahResult.fromJson(Map<String, dynamic> data) => NasabahResult(
status: data["status"],
data: List<Nasabah>.from(
data["data"].map((item) => Nasabah.fromJson(item))),
);
}
NasabahResult nasabahResultFromJson(String jsonData) {
final data = json.decode(jsonData);
return NasabahResult.fromJson(data);
}
String nasabahToJson(Nasabah nasabah) {
final jsonData = nasabah.toJson();
return json.encode(jsonData);
}
Service
import 'package:flutter_auth/Models/nasabah.dart';
import 'dart:convert';
import 'package:http/http.dart' show Client;
class ApiService {
final String baseUrl = '192.168.100.242:8080';
Client client = Client();
Future<List<Nasabah>> getNasabah() async {
final response = await client.get('http://$baseUrl/api/mstdebitur');
print(response.body);
if (response.statusCode == 200) {
final nasabah = (json.decode(response.body) as List)
.map((e) => Nasabah.fromMap(e))
.toList();
return nasabah;
} else {
throw Exception('Failed to load post');
}
}
Future<bool> createNasabah(Nasabah data) async {
String url = new Uri.http("$baseUrl", "/api/mstdebitur/").toString();
final response = await client.post(url,
headers: {"Content-Type": "application/json"},
body: nasabahToJson(data));
if (response.statusCode == 201) {
return true;
} else {
return false;
}
}
Future<bool> updateNasabah(Nasabah data) async {
String url =
new Uri.http("$baseUrl", "/api/mstdebitur/${data.id}").toString();
final response = await client.put(url,
headers: {"Content-Type": "application/json"},
body: nasabahToJson(data));
if (response.statusCode == 200) {
return true;
} else {
return false;
}
}
Future<bool> deleteNasabah(int id) async {
String url = new Uri.http("$baseUrl", "/api/mstdebitur/$id").toString();
final response = await client.delete(url);
if (response.statusCode == 200) {
return true;
} else {
return false;
}
}
}
Home
import 'package:flutter/material.dart';
import 'package:flutter_auth/Models/nasabah.dart';
import 'package:flutter_auth/network/nasabah_service.dart';
import 'FormAddNasabah.dart';
import 'ListNasabah.dart';
GlobalKey<ScaffoldState> _scaffoldState = GlobalKey<ScaffoldState>();
// ignore: must_be_immutable
class DataNasabah extends StatefulWidget {
DataNasabah({Key key}) : super(key: key);
String title;
#override
_DataNasabahState createState() => _DataNasabahState();
}
class _DataNasabahState extends State<DataNasabah> {
ApiService apiService;
ListNasabah _listNasabah;
List<Nasabah> data;
#override
void initState() {
super.initState();
apiService = ApiService();
_listNasabah = new ListNasabah(apiService: apiService);
}
#override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldState,
appBar: AppBar(
title: Text(
'Data Nasabah',
style: TextStyle(color: Colors.white),
),
actions: <Widget>[
GestureDetector(
onTap: () async {
var result = await Navigator.push(
_scaffoldState.currentContext,
MaterialPageRoute(builder: (BuildContext context) {
return FormAddNasabah(nasabah: null);
}),
);
if (result != null) {
setState(() {});
}
},
child: Padding(
padding: const EdgeInsets.only(right: 16.0),
child: Icon(
Icons.add,
color: Colors.white,
),
),
)
],
),
body: _listNasabah.createViewList(),
);
}
}
List
import 'package:flutter/material.dart';
import 'package:flutter_auth/Models/nasabah.dart';
import 'package:flutter_auth/network/nasabah_service.dart';
import 'package:flutter_auth/screens/Menu/DataNasabah/FormAddNasabah.dart';
import 'package:flutter_auth/screens/Menu/DataNasabah/NasabahHome.dart';
import 'package:rflutter_alert/rflutter_alert.dart';
class ListNasabah {
ApiService apiService;
ListNasabah({this.apiService});
Widget createViewList() {
return SafeArea(
child: FutureBuilder(
future: apiService.getNasabah(),
builder: (BuildContext context, AsyncSnapshot<List<Nasabah>> snapshot) {
if (snapshot.hasError) {
return Center(
child: Text(
'Something wrong with message: ${snapshot.error.toString()}',
textAlign: TextAlign.center,
),
);
} else if (snapshot.connectionState == ConnectionState.done) {
List<Nasabah> nasabah = snapshot.data;
return nasabahListView(nasabah);
} else {
return Center(
child: CircularProgressIndicator(),
);
}
},
),
);
}
Widget nasabahListView(List<Nasabah> listnasabah) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0),
child: ListView.builder(
shrinkWrap: true,
itemBuilder: (context, index) {
Nasabah nasabah = listnasabah[index];
return Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Card(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
nasabah.nama_debitur,
style: Theme.of(context).textTheme.bodyText1,
),
Text(nasabah.alamat),
Text(nasabah.no_ktp),
Text(nasabah.no_telp),
Text(nasabah.no_selular),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
FlatButton(
onPressed: () {
apiService.deleteNasabah(nasabah.id).then((value) =>
Navigator.of(context).pushNamed('start'));
},
child: Text(
"Hapus",
style: TextStyle(color: Colors.red),
),
),
FlatButton(
onPressed: () async {
var result = await Navigator.push(context,
MaterialPageRoute(builder: (context) {
return FormAddNasabah(
nasabah: nasabah,
);
}));
},
child: Text(
'Edit',
style: TextStyle(color: Colors.blue),
),
),
],
)
],
),
),
),
);
},
itemCount: listnasabah.length,
),
);
}
}
Form
import 'package:flutter/material.dart';
import 'package:flutter_auth/Models/nasabah.dart';
import 'package:flutter_auth/network/nasabah_service.dart';
import 'package:flutter_auth/screens/Menu/DataNasabah/NasabahHome.dart';
import 'package:rflutter_alert/rflutter_alert.dart';
class FormAddNasabah extends StatefulWidget {
Nasabah nasabah;
FormAddNasabah({this.nasabah});
#override
_FormAddNasabahState createState() => _FormAddNasabahState();
}
class _FormAddNasabahState extends State<FormAddNasabah> {
ApiService apiService;
TextEditingController _contNama = TextEditingController();
TextEditingController _contAlamat = TextEditingController();
TextEditingController _contNoTelp = TextEditingController();
TextEditingController _contNoKtp = TextEditingController();
TextEditingController _contNoSelular = TextEditingController();
#override
void initState() {
super.initState();
apiService = ApiService();
if (widget.nasabah != null) {
_contNama.text = widget.nasabah.nama_debitur;
_contAlamat.text = widget.nasabah.alamat;
_contNoTelp.text = widget.nasabah.no_telp;
_contNoKtp.text = widget.nasabah.no_ktp;
_contNoSelular.text = widget.nasabah.no_selular;
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
iconTheme: IconThemeData(color: Colors.white),
title: Text(
widget.nasabah == null ? "Tambah Nasabah" : "Edit Nasabah",
style: TextStyle(color: Colors.white),
),
),
body: Stack(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
_buildTextField(_contNama, "Nama Nasabah"),
_buildTextField(_contAlamat, "Alamat"),
_buildTextField(_contNoTelp, "No Telp"),
_buildTextField(_contNoKtp, "No KTP"),
_buildTextField(_contNoSelular, "No Selular"),
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: RaisedButton(
child: Text(widget.nasabah == null ? "Tambah" : "Edit"),
color: Colors.blue,
onPressed: () {
int id = 0;
if (widget.nasabah != null) {
id = widget.nasabah.id;
}
Nasabah nasabah = Nasabah(
id: id,
nama_debitur: _contNama.text,
alamat: _contAlamat.text,
no_telp: _contNoTelp.text,
no_ktp: _contNoKtp.text,
no_selular: _contNoSelular.text);
if (widget.nasabah == null) {
apiService.createNasabah(nasabah);
} else {
apiService.updateNasabah(nasabah);
}
Navigator.of(context)
.pushNamed('start')
.whenComplete(() => Navigator.pop(context));
},
),
)
],
),
)
],
),
);
}
Widget _buildTextField(TextEditingController _cont, String label) {
return TextField(
controller: _cont,
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
labelText: label,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
),
),
);
}
}
Thank you for your attention!

Troubles with making a Favorite page with Hive DB Flutter

Hello everyone here's my test app and I have some problems with making a Favorite page section where you can tap on button and add the item into fav page.
I'm receiving a data from API and implementing it by Listview.builder
Here are some photos of how it should look like:
Home page
Favorite page
main.dart, here I'm openning a box called 'favorites_box'
import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart';
import 'package:hive/hive.dart';
import 'package:hive_flutter/hive_flutter.dart';
void main() async{
await GetStorage.init();
await Hive.openBox('favorites_box');
runApp(MainPage());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return GetMaterialApp(
initialRoute: '/',
getPages: [
GetPage(name: '/', page: () => MyApp()),
GetPage(name: '/main-page', page: () => MainPage()),
GetPage(name: '/favorite_page', page: () => FavoritePage()),
// Dynamic route
],
home: MainPage(),
);
}
}
Well here's a code of home page:
main_page.dart
import 'package:flutter/material.dart';
import '../View/listview_api.dart';
class MainPage extends StatefulWidget {
#override
State<MainPage> createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> {
int currentIndex = 0;
List<BottomNavigationBarItem>? items;
final screens = [
HomePage(),
HomePage()
FavoritePage(),
HomePage()
];
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: SafeArea(
child: Scaffold(
appBar: AppBar(
backgroundColor: Colors.white,
title: Container(
width: double.infinity,
height: 40,
color: Colors.white,
child: Center(
child: TextField(
decoration: InputDecoration(
border: OutlineInputBorder(
),
hintText: 'Searching',
prefixIcon: Icon(Icons.search),
suffixIcon: Icon(Icons.notifications)),
),
),
),
),
body: screens[currentIndex],
bottomNavigationBar: BottomNavigationBar(
unselectedItemColor: Colors.grey,//AppColors.unselectedBottomNavItem,
selectedItemColor: Colors.blue,//AppColors.assets,
onTap: (index) => setState(() {
currentIndex = index;
}),//controller.setMenu(BottomMenu.values[pos]),
//currentIndex: ,//controller.bottomMenu.index,
type: BottomNavigationBarType.fixed,
backgroundColor: Colors.white,
currentIndex: currentIndex,
selectedLabelStyle: const TextStyle(
fontSize: 10,
fontWeight: FontWeight.w500,
),
unselectedLabelStyle: const TextStyle(
fontSize: 10,
fontWeight: FontWeight.w500,
),
elevation: 8,
items: [
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'Home',
backgroundColor: Colors.blue,
),
BottomNavigationBarItem(
icon: Icon(Icons.add_shopping_cart),
label: 'Shopping cart',
backgroundColor: Colors.red,
),
BottomNavigationBarItem(
icon: Icon(Icons.favorite),
label: 'Favorite',
backgroundColor: Colors.green,
),
BottomNavigationBarItem(
icon: Icon(Icons.person),
label: 'Profile',
backgroundColor: Colors.yellow,
),
],
),
),
),
);
}
}
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return SafeArea(
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Center(
child: Padding(
padding: EdgeInsets.all(10.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
//Image.asset('images/image0.jpg'),
SizedBox(
height: 25.0,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'New!',
textAlign: TextAlign.left,
style: TextStyle(
fontSize: 25.0,
fontWeight: FontWeight.bold,
),
),
IconButton(
onPressed: () {},
icon: Icon(
Icons.arrow_forward_outlined,
),
),
],
),
SizedBox(
height: 25.0,
),
SizedBox(
height: 300.0,
width: double.infinity,
child: ListViewAPI(),
),
],
),
),
),
),
);
}
}
And now, below is a code of ListViewAPI(), here I've added the elements which I tap to the box('favorites_box'): listview_api.dart
import 'package:flutter/material.dart';
import 'package:hive/hive.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
String? stringResponse;
Map? mapResponse;
Map? dataResponse;
List? listResponse;
class ListViewAPI extends StatefulWidget {
const ListViewAPI({Key? key}) : super(key: key);
#override
_ListViewAPIState createState() => _ListViewAPIState();
}
class _ListViewAPIState extends State<ListViewAPI> {
Future apiCall() async {
http.Response response;
response = await http.get(Uri.parse("https://api.client.macbro.uz/v1/product"));
if(response.statusCode == 200) {
setState(() {
// stringResponse = response.body;
mapResponse = jsonDecode(response.body);
listResponse = mapResponse!['products'];
});
}
}
#override
void initState() {
super.initState();
apiCall();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scrollbar(
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
return Stack(
children: [
Card(
child: Image.network(
listResponse![index]['image'],
),
),
Positioned(
right: 0,
child: InkWell(
child: IconButton(
onPressed: () async {
await Hive.box('favorites_box').put(listResponse![index]['image'], listResponse);
},
icon: Icon(
Icons.favorite_rounded,
color: Colors.red,
),
),
),
),
],
);
},
itemCount: listResponse == null ? 0 : listResponse!.length,
),
),
);
}
}
So here, I created a list, and tried to save the elements from box named "favorites_box" and got data which was added while I tap favorite IconButton upper but without success( :
favorite_page.dart
import 'package:flutter/material.dart';
import 'package:hive/hive.dart';
import 'package:hive_flutter/hive_flutter.dart';
import '../View/gridview_api.dart';
class FavoritePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: ValueListenableBuilder(
valueListenable: Hive.box('favorites_box').listenable(),
builder: (context, box, child) {
List posts = List.from(Hive.box('favorites_box').values);
return ListView.builder(
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
return Column(
children: [
Text(
'List of favorite products'
),
Card(
child: posts[index] == null ? Text('nothing(') : posts[index],
// child: Hive.box('favorites_box').get(listResponse),
),
],
);
},
);
},
),
);
}
}
I'll be grateful if someone could help me with this problem, as I'm trying to fix this issue for a couple of days
P.s. I'm so sorry for some inconveniences, I'm a novice yet that's why hope you'll understand me
Thanks!
Alright. I now have a solution. It is a bit more complex than what you started with but it worked during testing.
Using https://marketplace.visualstudio.com/items?itemName=hirantha.json-to-dart I created a model class from the API data JSON. One for the Product and one for the Price map inside of Product.
product_model.dart
import 'dart:convert';
import 'package:equatable/equatable.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'price.dart';
part 'product_model.g.dart';
#HiveType(typeId: 1)
class ProductModel extends Equatable {
#HiveField(0)
final String? id;
#HiveField(1)
final String? name;
#HiveField(2)
final String? slug;
#HiveField(3)
final bool? active;
#HiveField(4)
final String? image;
#HiveField(5)
final String? code;
#HiveField(6)
final String? order;
#HiveField(7)
final int? cheapestPrice;
#HiveField(8)
final Price? price;
#HiveField(9)
final int? discount;
const ProductModel({
this.id,
this.name,
this.slug,
this.active,
this.image,
this.code,
this.order,
this.cheapestPrice,
this.price,
this.discount,
});
factory ProductModel.fromMap(Map<String, dynamic> data) => ProductModel(
id: data['id'] as String?,
name: data['name'] as String?,
slug: data['slug'] as String?,
active: data['active'] as bool?,
image: data['image'] as String?,
code: data['code'] as String?,
order: data['order'] as String?,
cheapestPrice: data['cheapest_price'] as int?,
price: data['price'] == null
? null
: Price.fromMap(data['price'] as Map<String, dynamic>),
discount: data['discount'] as int?,
);
Map<String, dynamic> toMap() => {
'id': id,
'name': name,
'slug': slug,
'active': active,
'image': image,
'code': code,
'order': order,
'cheapest_price': cheapestPrice,
'price': price?.toMap(),
'discount': discount,
};
/// `dart:convert`
///
/// Parses the string and returns the resulting Json object as [ProductModel].
factory ProductModel.fromJson(String data) {
return ProductModel.fromMap(json.decode(data) as Map<String, dynamic>);
}
/// `dart:convert`
///
/// Converts [ProductModel] to a JSON string.
String toJson() => json.encode(toMap());
ProductModel copyWith({
String? id,
String? name,
String? slug,
bool? active,
String? image,
String? code,
String? order,
int? cheapestPrice,
Price? price,
int? discount,
}) {
return ProductModel(
id: id ?? this.id,
name: name ?? this.name,
slug: slug ?? this.slug,
active: active ?? this.active,
image: image ?? this.image,
code: code ?? this.code,
order: order ?? this.order,
cheapestPrice: cheapestPrice ?? this.cheapestPrice,
price: price ?? this.price,
discount: discount ?? this.discount,
);
}
#override
bool get stringify => true;
#override
List<Object?> get props {
return [
id,
name,
slug,
active,
image,
code,
order,
cheapestPrice,
price,
discount,
];
}
}
price.dart
import 'dart:convert';
import 'package:equatable/equatable.dart';
import 'package:hive_flutter/hive_flutter.dart';
part 'price.g.dart';
#HiveType(typeId: 2)
class Price extends Equatable {
#HiveField(0)
final int? price;
#HiveField(1)
final int? oldPrice;
#HiveField(2)
final int? uzsPrice;
#HiveField(3)
final int? secondPrice;
#HiveField(4)
final int? secondUzsPrice;
const Price({
this.price,
this.oldPrice,
this.uzsPrice,
this.secondPrice,
this.secondUzsPrice,
});
factory Price.fromMap(Map<String, dynamic> data) => Price(
price: data['price'] as int?,
oldPrice: data['old_price'] as int?,
uzsPrice: data['uzs_price'] as int?,
secondPrice: data['second_price'] as int?,
secondUzsPrice: data['second_uzs_price'] as int?,
);
Map<String, dynamic> toMap() => {
'price': price,
'old_price': oldPrice,
'uzs_price': uzsPrice,
'second_price': secondPrice,
'second_uzs_price': secondUzsPrice,
};
/// `dart:convert`
///
/// Parses the string and returns the resulting Json object as [Price].
factory Price.fromJson(String data) {
return Price.fromMap(json.decode(data) as Map<String, dynamic>);
}
/// `dart:convert`
///
/// Converts [Price] to a JSON string.
String toJson() => json.encode(toMap());
Price copyWith({
int? price,
int? oldPrice,
int? uzsPrice,
int? secondPrice,
int? secondUzsPrice,
}) {
return Price(
price: price ?? this.price,
oldPrice: oldPrice ?? this.oldPrice,
uzsPrice: uzsPrice ?? this.uzsPrice,
secondPrice: secondPrice ?? this.secondPrice,
secondUzsPrice: secondUzsPrice ?? this.secondUzsPrice,
);
}
#override
bool get stringify => true;
#override
List<Object?> get props {
return [
price,
oldPrice,
uzsPrice,
secondPrice,
secondUzsPrice,
];
}
}
I then used https://docs.hivedb.dev/#/custom-objects/generate_adapter to create adapters for both of those. You can read the documentation to see how that is done using build_runner and the hive_generator packages.
In main.dart I registered both of the adapters and opened up a box with the ProductModel type from product_model.dart.
main.dart
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:test/product_model/price.dart';
import 'package:test/product_model/product_model.dart';
import 'favorite_page.dart';
import 'homepage.dart';
void main() async {
// await GetStorage.init();
await Hive.initFlutter();
Hive.registerAdapter(PriceAdapter());
Hive.registerAdapter(ProductModelAdapter());
await Hive.openBox<ProductModel>('favorites_box');
runApp(MainPage());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return GetMaterialApp(
initialRoute: '/',
getPages: [
GetPage(name: '/', page: () => MyApp()),
GetPage(name: '/main-page', page: () => MainPage()),
GetPage(name: '/favorite_page', page: () => FavoritePage()),
// Dynamic route
],
home: MainPage(),
);
}
}
listview_api.dart is mostly the same with the exception of mapping the products from listResponse to ProductModel objects.
import 'package:flutter/material.dart';
import 'package:hive/hive.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'package:test/product_model/product_model.dart';
String? stringResponse;
Map? mapResponse;
Map? dataResponse;
List? listResponse;
class ListViewAPI extends StatefulWidget {
const ListViewAPI({Key? key}) : super(key: key);
#override
_ListViewAPIState createState() => _ListViewAPIState();
}
class _ListViewAPIState extends State<ListViewAPI> {
Future apiCall() async {
http.Response response;
response =
await http.get(Uri.parse("https://api.client.macbro.uz/v1/product"));
if (response.statusCode == 200) {
setState(() {
// stringResponse = response.body;
mapResponse = jsonDecode(response.body);
listResponse = mapResponse!['products'];
listResponse =
listResponse!.map((e) => ProductModel.fromMap(e)).toList(); // Map all of the products in listResponse to a ProductModel object.
});
}
}
#override
void initState() {
super.initState();
apiCall();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scrollbar(
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
return Stack(
children: [
Card(
child: Image.network(
listResponse![index].image!,
),
),
Positioned(
right: 0,
child: InkWell(
child: IconButton(
onPressed: () async {
await Hive.box<ProductModel>('favorites_box').put(
listResponse![index].image, listResponse![index]);
},
icon: Icon(
Icons.favorite_rounded,
color: Colors.red,
),
),
),
),
],
);
},
itemCount: listResponse == null ? 0 : listResponse!.length,
),
),
);
}
}
homepage.dart is unchanged.
favorite_page.dart was changed to a stateful widget and then gets the box values on init.
import 'package:flutter/material.dart';
import 'package:hive/hive.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:test/product_model/product_model.dart';
class FavoritePage extends StatefulWidget {
#override
State<FavoritePage> createState() => _FavoritePageState();
}
class _FavoritePageState extends State<FavoritePage> {
var posts;
#override
void initState() {
super.initState();
posts = Hive.box<ProductModel>('favorites_box').values.toList();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView.builder(
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
return Stack(
children: [
Card(
child: Image.network(
posts[index].image!,
),
),
Positioned(
right: 0,
child: InkWell(
child: IconButton(
onPressed: () async {
await Hive.box<ProductModel>('favorites_box')
.delete(posts[index]);
},
icon: Icon(
Icons.favorite_rounded,
color: Colors.red,
),
),
),
),
],
);
},
itemCount: posts == null ? 0 : posts.length,
),
);
}
}
I really encourage you to read the documentation on Hive as it contains a wealth of information. Another tip when coding with hive is to make sure you are clearing out the storage and cache for your emulator or physical device regularly. I have had too many headaches dealing with errors in Hive simply because I forgot to clear the storage and cache which was resulting in bad data despite having changed my source code.
I don't believe this is a problem with your code. However, I do recommend creating a model class for your data and maybe using a FutureBuilder https://api.flutter.dev/flutter/widgets/FutureBuilder-class.html.
I believe the problem is that you have not updated your AndroidManifest.xml file to allow for internet connectivity.
Try adding:
<uses-permission android:name="android.permission.INTERNET" />
to your android\app\src\main\AndroidManifest.xml, above <application.
Further reading: https://flutter-examples.com/add-permissions-in-androidmanifest-xml-file/
After taking a closer look at your issue, I think I figured out the problem.
Hive requires an init:
void main() async {
// await GetStorage.init(); // Not sure why this was here but doesn't seem to be needed.
await Hive.initFlutter();
await Hive.openBox('favorites_box');
runApp(MainPage());
}
You were also missing a comma in main_page.dart
final screens = [
HomePage(),
HomePage() <----
FavoritePage(),
HomePage()
];
For your favorites page, I replaced the ValueListenableBuilder with just a ListView.builder:
class FavoritePage extends StatelessWidget {
List posts = List.from(Hive.box('favorites_box').values);
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView.builder(
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
return Stack(
children: [
Card(
child: Image.network(
posts[index]['image'],
),
),
Positioned(
right: 0,
child: InkWell(
child: IconButton(
onPressed: () async {
await Hive.box('favorites_box').delete(posts[index]);
},
icon: Icon(
Icons.favorite_rounded,
color: Colors.red,
),
),
),
),
],
);
},
itemCount: posts == null ? 0 : posts.length,
),
);
}
}
There is still an error when you try to use this that says that posts[index]['image'] type 'String' is not a subtype of type 'int' of 'index' but you can easily fix this by creating a model class and accessing everything with those properties. Using model class in flutter (dart) here is an example of a model class. Instead of using DocumentSnapshot, you can add a toList() or toMap() method.
Hope this helps. It is working on my emulator. but I am just printing out the full string instead of using the image in the Card child.
Example Model Class:
import 'dart:convert';
void main() async {
String data = '{"id":"626694d4f1ce2a0012f0fe1c","name":"JBL Party Box On-The-Go","slug":"jbl-party-box-on-the-go-juqgil2ep8ult","active":true,"image":"https://cdn.macbro.uz/macbro/1fad4f47-51f4-4f12-975b-657d780c98af","code":"","order":"0","cheapest_price":0,"price":{"price":520,"old_price":0,"uzs_price":5994000,"second_price":0,"second_uzs_price":7012500},"discount":0}';
var test = new ProductModel.fromJson(json.decode(data));
print(test.image);
}
class ProductModel {
String? name;
String? image;
ProductModel.fromJson(Map json) {
this.name = json['id'];
this.image = json['image'];
}
}

Flutter Getx - Sending the data to the other pages

How can I send the data I get from the API to the other pages? Before using getx i was sending with "widget.bla bla" but now i don't know how can i send it.
class HomePage extends StatelessWidget {
final AllCoinController allCoinController = Get.put(AllCoinController());
#override
Widget build(BuildContext context) {
return Scaffold(
body: Obx(
() => ListView.builder(
scrollDirection: Axis.vertical,
itemCount: allCoinController.coinList.length,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: GestureDetector(
onTap: () {
Get.to(CoinContent());
},
child: Container(
color: Colors.grey[700],
width: 150,
child: Row(
children: [
SizedBox(
width: 50,
height: 50,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Image.network(
allCoinController.coinList[index].image),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(allCoinController.coinList[index].name),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(allCoinController.coinList[index].symbol),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(allCoinController
.coinList[index].currentPrice
.toString()),
),
],
),
),
),
);
},
),
),
);
}
}
The page I want to send the data to:
class CoinContent extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text("coin name"),
),
body: Obx(
() => Center(
child: Column(
children: [
Text("coin data 1"),
Text("coin data 2"),
Text("coin data 3"),
Text("coin data 4"),
Text("coin data 5"),
Text("coin data 6"),
],
),
),
),
);
}
}
And my last question codes are not found automatically when using Getx. Example:
Text(allCoinController.coinList[index].currentPrice.toString()),
I get the same data without using getx and there was no problem. But when using Getx the "currentPrice" code is not automatically found and does not appear. I need to copy the code to write.
My controller:
import 'dart:async';
import 'package:coin_finder/models/btc_eth_bnb_model.dart';
import 'package:get/get.dart';
import 'package:http/http.dart' as http;
class AllCoinController extends GetxController {
var coinList = [].obs;
final url = Uri.parse("api url")
Future callAllCoins() async {
try {
final response = await http.get(url);
if (response.statusCode == 200) {
List<dynamic> values = [];
values = allCoinsFromJson(response.body);
coinList.assignAll(values);
if (values.length > 0) {
for (int i = 0; i < values.length; i++) {
if (values[i] != null) {
coinList.add(values[i]);
}
}
}
return coinList;
} else {
print(response.statusCode);
}
} catch (e) {
print(e.toString());
}
}
#override
void onInit() {
callAllCoins();
Timer.periodic(Duration(minutes: 5), (timer) => callAllCoins());
super.onInit();
}
}
Model:
import 'dart:convert';
List<AllCoins> allCoinsFromJson(String str) =>
List<AllCoins>.from(json.decode(str).map((x) => AllCoins.fromJson(x)));
String allCoinsToJson(List<AllCoins> data) =>
json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class AllCoins {
AllCoins({
required this.symbol,
required this.name,
required this.image,
required this.currentPrice,
});
String symbol;
String name;
String image;
num currentPrice;
factory AllCoins.fromJson(Map<String, dynamic> json) => AllCoins(
symbol: json["symbol"],
name: json["name"],
image: json["image"],
currentPrice: json["current_price"],
);
Map<String, dynamic> toJson() => {
"symbol": symbol,
"name": name,
"image": image,
"current_price": currentPrice,
};
}
Dart version: sdk: ">=2.12.0 <3.0.0"
in home page Get.to(CoinContent(),arguments:
allCoinController.coinList[index] )
//
class CoinContent extends StatelessWidget {
#override
Widget build(BuildContext context) {
final data = ModalRoute.of(context)!.settings.arguments as
AllCoins;
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text("coin name"),
),
body:Center(
child: Column(
children: [
Text("${data.name}"),
],
),
),
);
}
}
in this case we aren't using agrs in constructor
instead of routing like that Get.to(MyScreen());
you should use Get.to(MyScreen(), arguments: [1,2,3]);
you can access them by using Get.arguments it should return a List
Note: The arguments will not change while using the app until you override it by routing to another screen with args

Dropdown in flutter from LIST

Displaying the data from my API based on the Dropdown selected value. I want to display on the same page. The data from the server(response) is displaying on the console. But still, this data is not displaying.
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:http/http.dart' as http;
//import 'package:json_parsing_example/model2.dart';
//import 'package:json_parsing_example/models.dart'
List<YouModel> youModelFromJson(String str) => List<YouModel>.from(json.decode(str).map((x) => YouModel.fromJson(x)));
String youModelToJson(List<YouModel> data) => json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class YouModel {
String columnName;
YouModel({
this.columnName,
});
factory YouModel.fromJson(Map<String, dynamic> json) => YouModel(
columnName: json["column_name"],
);
Map<String, dynamic> toJson() => {
"column_name": columnName,
};
}
UserModel userModelFromJson(String str) => UserModel.fromJson(json.decode(str));
String userModelToJson(UserModel data) => json.encode(data.toJson());
class UserModel {
String username;
String name;
UserModel({
this.username,
this.name,
});
factory UserModel.fromJson(Map<String, dynamic> json) => UserModel(
username: json["username"],
name: json["Name"],
);
Map<String, dynamic> toJson() => {
"username": username,
"Name": name,
};
}
class Addoffers2 extends StatefulWidget {
#override
State<StatefulWidget> createState() => _Addoffers2State();
}
class _Addoffers2State extends State<Addoffers2> {
List<String> _companies = [];
bool _isLoading = false;
String _selectedCompany;
#override
void initState() {
super.initState();
_selectedCompany=null;
_getcompanylist();
}
Future<String> loadFromAssets() async {
return await rootBundle.loadString('json/parse.json');
}
_getcompanylist() async {
setState(() {
_isLoading = true;
});
print("getting..");
final responseStr =
await http.get('http://10.0.2.2/Flutter/GetCompanieslist.php');
//String responseStr = await loadFromAssets();
final listData = youModelFromJson(responseStr.body);
for(int i=0;i<listData.length;i++)
{
print('this is the list :'+listData[i].columnName);
// _companies.add(listData[i].columnName);
}
// above method is the standard method to get creating a model class and then get the list of strings
// I have just shown you but example is according to you code .
// this above loadFromAssets is that you hit the api and you get the json string response
// i have created a dummy json file where i can the String.
// Else everything is the same as below you just have to pass the response.body to the json.decode method.
var jsonData = json.decode(responseStr.body);
for (var u in jsonData) {
_companies.add(u.toString().substring(14, u.toString().length - 1));
}
for (int i = 0; i < _companies.length; i++) {
print(_companies[i].toString());
}
setState(() {
_isLoading = false;
});
}
#override
Widget build(BuildContext context) {
//double width = MediaQuery.of(context).size.width;
//double height = MediaQuery.of(context).size.height;
return MaterialApp(
//color: Colors.red,
home: Scaffold(
backgroundColor: Colors.red,
appBar: AppBar(
backgroundColor: Theme.of(context).backgroundColor,
title: Text("Add.."),
),
body: Container(
color: Colors.blue,
// just put your height i have modified it replace it by height / 8
child: _isLoading
? CircularProgressIndicator()
: Center(
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
//MainAxisAlignment: MainAxisAlignment.spaceBetween,
Text('Choose..'),
DropdownButtonHideUnderline(
child: DropdownButton(
// hint: Text('Choose Company'), // Not necessary for Option 1
value: _selectedCompany,
onChanged: (newValue) {
setState(() {
_selectedCompany = newValue;
// here i have taken the boolen variable to show and hide the list if you have not seleted the value from the dropdown the it will show the text and if selected the it will show you the list.
});
print(_selectedCompany);
},
items: _companies.map((company) {
return DropdownMenuItem(
child: new Text(company.toString()),
value: company,
);
}).toList(),
),
),
],
),
),
),
// this is to to check for the initial if string is null then show the text widget.
// else if the value is selected then it will show the listview
_selectedCompany == null
? Text('Select the dropdown value for list to appear.')// sample text you can modify
: Padding(
padding: const EdgeInsets.all(0.0),
child: Container(
height: 100,
color: Theme.of(context).backgroundColor,
child: new FutureBuilder(
future: _getUsers(
_selectedCompany), // a Future<String> or null
builder: (BuildContext context,
AsyncSnapshot snapshot) {
if (snapshot.connectionState ==
ConnectionState.waiting) {
return Container(
child: Center(
child: new CircularProgressIndicator(
backgroundColor: Colors.white,
),
));
}
if (snapshot.hasError) {
return Center(
child: new Text(
'Error ${snapshot.error}'),
);
} else {
return Center(
child: Padding(
padding: const EdgeInsets.fromLTRB(
5.0, 8.0, 5.0, 8.0),
child: ListView.builder(
itemCount: snapshot.data.length,
itemBuilder:
(BuildContext context,
int index) {
List<UserModel> user =
snapshot.data;
var username =
user[index].username;
var stuname =
user[index].name;
print(
'This is the user name :$username');
print(
'This is the name : $stuname');
//var title=snapshot.data[index]["Title"];
// new Text(parsedDate.toString());
return StudentList2(
regdNo: username,
name: stuname);
}),
),
);
}
}),
),
),
],
)),
)),
);
}
}
Future<String> loadFromAssets2() async {
return await rootBundle.loadString('json/parse2.json');
}
// the above method is just for the sample purpose where you get you json String after hitting the api call for _getUsers method
Future<List<UserModel>> _getUsers(String selectedcompany) async {
// here you call you api and you get the response
var url = 'https://10.0.2.2/Flutter/getstudentdata.php;
var data = { 'company': selectedcompany};
// Starting Web Call with data.
var response = await http.post(url, body: json.encode(data));
print(response.body);
//String responseStr = await loadFromAssets2();
final userModel = userModelFromJson(response.body);
// I have just made the model class for where fromt he below you get the complete object and then added to the list and returned.
List<UserModel> users = [];
users.add(userModel);
print('This is the name : ${users[0].name}'); // Even this also not getting printed
return users;
}
class StudentList2 extends StatefulWidget {
final regdNo;
final name;
const StudentList2({
Key key,
this.regdNo,
this.name,
}) : super(key: key);
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<StudentList2> {
bool visible = false;
#override
Widget build(BuildContext context) {
print(widget.regdNo.toString());
return Padding(
padding: const EdgeInsets.symmetric(vertical: 5.0),
child: new Card(
color: Theme.of(context).primaryColor,
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.fromLTRB(8.0, 8.0, 8.0, 2.0),
child: Container(
child: new Text(
widget.regdNo.toUpperCase(),
style: TextStyle(
color: Colors.yellowAccent,
fontWeight: FontWeight.bold,
fontSize: 15.0,
),
),
),
),
ListTile(
title: new Text(
widget.regdNo,
style: TextStyle(
color: Colors.black,
fontSize: 14.0,
),
),
subtitle: new Text(
(widget.name),
style: TextStyle(
color: Colors.black,
fontSize: 15.0,
),
),
),
//
],
)),
);
}
}
I am able to retrieve the data from the server and print it on the console. Still, the data is not displaying. I do not know where I did the mistake.
So I have completely updated the answer and there are many things that you don't follow according to the global standard.
So I have listed some of the key things that you should follow :
Following is you company list json :
[
{
"column_name": "ABC"
},
{
"column_name": "XYZ"
}
]
Following is the get user json that you will get :
{"username":"1111","Name":"ABC" }
And Later the model class I have create accordingly to the json that you provided and then you can create your own based in the added json.
There are Two model classes that I have created :
First model class is for the company :
// To parse this JSON data, do
//
// final youModel = youModelFromJson(jsonString);
import 'dart:convert';
List<YouModel> youModelFromJson(String str) => List<YouModel>.from(json.decode(str).map((x) => YouModel.fromJson(x)));
String youModelToJson(List<YouModel> data) => json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class YouModel {
String columnName;
YouModel({
this.columnName,
});
factory YouModel.fromJson(Map<String, dynamic> json) => YouModel(
columnName: json["column_name"],
);
Map<String, dynamic> toJson() => {
"column_name": columnName,
};
}
second mode class is for the user :
// To parse this JSON data, do
//
// final userModel = userModelFromJson(jsonString);
import 'dart:convert';
UserModel userModelFromJson(String str) => UserModel.fromJson(json.decode(str));
String userModelToJson(UserModel data) => json.encode(data.toJson());
class UserModel {
String username;
String name;
UserModel({
this.username,
this.name,
});
factory UserModel.fromJson(Map<String, dynamic> json) => UserModel(
username: json["username"],
name: json["Name"],
);
Map<String, dynamic> toJson() => {
"username": username,
"Name": name,
};
}
Below is the main ui file just Check the comments that I have made so that it will be helpful for you .
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:json_parsing_example/model2.dart';
import 'package:json_parsing_example/models.dart';
void main() => runApp(Addoffers());
class Addoffers extends StatefulWidget {
#override
State<StatefulWidget> createState() => _AddoffersState();
}
class _AddoffersState extends State<Addoffers> {
List<String> _companies = [];
bool _isLoading = false;
String _selectedCompany;
#override
void initState() {
super.initState();
_selectedCompany=null;
_getcompanylist();
}
Future<String> loadFromAssets() async {
return await rootBundle.loadString('json/parse.json');
}
_getcompanylist() async {
setState(() {
_isLoading = true;
});
print("getting..");
/* final response =
await http.get('http://10.0.2.2/Flutter/GetCompanieslist.php'); */
String responseStr = await loadFromAssets();
final listData = youModelFromJson(responseStr);
for(int i=0;i<listData.length;i++)
{
print('this is the list :'+listData[i].columnName);
// _companies.add(listData[i].columnName);
}
// above method is the standard method to get creating a model class and then get the list of strings
// I have just shown you but example is according to you code .
// this above loadFromAssets is that you hit the api and you get the json string response
// i have created a dummy json file where i can the String.
// Else everything is the same as below you just have to pass the response.body to the json.decode method.
var jsonData = json.decode(responseStr);
for (var u in jsonData) {
_companies.add(u.toString().substring(14, u.toString().length - 1));
}
for (int i = 0; i < _companies.length; i++) {
print(_companies[i].toString());
}
setState(() {
_isLoading = false;
});
}
#override
Widget build(BuildContext context) {
//double width = MediaQuery.of(context).size.width;
//double height = MediaQuery.of(context).size.height;
return MaterialApp(
//color: Colors.red,
home: Scaffold(
backgroundColor: Colors.red,
appBar: AppBar(
backgroundColor: Theme.of(context).backgroundColor,
title: Text("Add.."),
),
body: Container(
color: Colors.blue,
// just put your height i have modified it replace it by height / 8
child: _isLoading
? CircularProgressIndicator()
: Center(
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
//MainAxisAlignment: MainAxisAlignment.spaceBetween,
Text('Choose..'),
DropdownButtonHideUnderline(
child: DropdownButton(
// hint: Text('Choose Company'), // Not necessary for Option 1
value: _selectedCompany,
onChanged: (newValue) {
setState(() {
_selectedCompany = newValue;
// here i have taken the boolen variable to show and hide the list if you have not seleted the value from the dropdown the it will show the text and if selected the it will show you the list.
});
print(_selectedCompany);
},
items: _companies.map((company) {
return DropdownMenuItem(
child: new Text(company.toString()),
value: company,
);
}).toList(),
),
),
],
),
),
),
// this is to to check for the initial if string is null then show the text widget.
// else if the value is selected then it will show the listview
_selectedCompany == null
? Text('Select the dropdown value for list to appear.')// sample text you can modify
: Padding(
padding: const EdgeInsets.all(0.0),
child: Container(
height: 100,
color: Theme.of(context).backgroundColor,
child: new FutureBuilder(
future: _getUsers(
_selectedCompany), // a Future<String> or null
builder: (BuildContext context,
AsyncSnapshot snapshot) {
if (snapshot.connectionState ==
ConnectionState.waiting) {
return Container(
child: Center(
child: new CircularProgressIndicator(
backgroundColor: Colors.white,
),
));
}
if (snapshot.hasError) {
return Center(
child: new Text(
'Error ${snapshot.error}'),
);
} else {
return Center(
child: Padding(
padding: const EdgeInsets.fromLTRB(
5.0, 8.0, 5.0, 8.0),
child: ListView.builder(
itemCount: snapshot.data.length,
itemBuilder:
(BuildContext context,
int index) {
List<UserModel> user =
snapshot.data;
var username =
user[index].username;
var stuname =
user[index].name;
print(
'This is the user name :$username');
print(
'This is the name : $stuname');
//var title=snapshot.data[index]["Title"];
// new Text(parsedDate.toString());
return StudentList2(
regdNo: username,
name: stuname);
}),
),
);
}
}),
),
),
],
)),
)),
);
}
}
Future<String> loadFromAssets2() async {
return await rootBundle.loadString('json/parse2.json');
}
// the above method is just for the sample purpose where you get you json String after hitting the api call for _getUsers method
Future<List<UserModel>> _getUsers(String selectedcompany) async {
/* var data = await http.post("http://10.0.2.2/Flutter/getstdata.php", body: {
"company": selectedcompany,
//print(data.body);
}); */
// here you call you api and you get the response
String responseStr = await loadFromAssets2();
final userModel = userModelFromJson(responseStr);
// I have just made the model class for where fromt he below you get the complete object and then added to the list and returned.
List<UserModel> users = [];
users.add(userModel);
print('This is the name : ${users[0].name}');
//final x=users.length.toString();
//debugPrint("records:" + users.length.toString());
//debugPrint("kkk:" + absentees.length.toString());
return users;
}
class StudentList2 extends StatefulWidget {
//MyHomePage(String branch);
final regdNo;
final name;
const StudentList2({
Key key,
this.regdNo,
this.name,
}) : super(key: key);
//final String branch;
//const StudentList({Key key, this.branch}) : super(key: key);
//MyHomePage(String branch);
// final String title;
// final String branch="";
// MyHomePage(String branch, {Key key, this.title}) : super(key: key);
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<StudentList2> {
bool visible = false;
//bool _btnEnabled = false;
//bool _validate = false;
// var _firstPress = true ;
//Color _iconColor = Colors.yellow;
//Color _iconColor2 = Colors.white;
//var poll;
//DateTime parsedDate;
#override
Widget build(BuildContext context) {
print(widget.regdNo.toString());
return Padding(
padding: const EdgeInsets.symmetric(vertical: 5.0),
child: new Card(
color: Theme.of(context).primaryColor,
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.fromLTRB(8.0, 8.0, 8.0, 2.0),
child: Container(
child: new Text(
widget.regdNo.toUpperCase(),
style: TextStyle(
color: Colors.yellowAccent,
fontWeight: FontWeight.bold,
fontSize: 15.0,
),
),
),
),
ListTile(
title: new Text(
widget.regdNo,
style: TextStyle(
color: Colors.black,
fontSize: 14.0,
),
),
subtitle: new Text(
(widget.name),
style: TextStyle(
color: Colors.black,
fontSize: 15.0,
),
),
),
//
],
)),
);
}
}
// This is not the good approach to create a model class just check the sample model class that i have created.
class User {
//final int index;
final String username;
final String name;
//final Float cgpa;
User(
this.username,
this.name,
);
}
And below is the sample Gif file for you :
As stated by #pskink the method _getcompanylist() is async. An async function runs asynchronously, which means that the rest of the program doesn't wait for it to complete. You can use a future builder to deal whit that or you can simply wait for it by using the await function. I believe that for your code snippet future builder is the better choice.