Fill list in flutter from other page - flutter

On fetchDept.dart I have:
Future<List<Dept>> fetchDept() async {
final response = await http.get(Uri.https('someurl.com', 'dept'));
if (response.statusCode == 200) {
List<Dept> dept = (json.decode(response.body)["items"] as List)
.map((data) => Dept.fromJson(data))
.toList();
return dept;
} else {
throw Exception('Error');
}
}
How on other dart page load data from fetchDept.dart (fetchDept) to deptList
Details.dart page:
import 'package:services/fetchDept.dart';
class DropListPage extends StatefulWidget {
#override
_DropListPageState createState() => _DropListPageState();
}
class _DropListPageState extends State<DropListPage> {
#override
void initState() {
fetchDept();
super.initState();
}
List deptList;
String _myDept;
//deptList ==> Set here data from fetchDept()
On Details.dart page I need to populate Dropdown list.

on the Details page, you could store your data into a List and use it to build your widgets, like this:
import 'package:services/fetchDept.dart';
class DropListPage extends StatefulWidget {
#override
_DropListPageState createState() => _DropListPageState();
}
class _DropListPageState extends State<DropListPage> {
List deptList=[];
#override
void initState() {
asyncMethod();
super.initState();
}
Future<void> asyncMethod() async{
List result = await fetchDept();
setState((){
deptList=result;
});
}
String _myDept;
//with the help of deptList you could build your widgets

Related

list access outside provider class

My problem is that when I access list under consumer and show into text widget it shows data. but when I use same list in initstate it shows null even when I use same list before return in consumer it shows null.
This is view:
class FilterView extends StatefulWidget {
const FilterView({super.key});
#override
State<FilterView> createState() => _FilterViewState();
}
class _FilterViewState extends State<FilterView> {
CategoryViewModel categoryViewModel = CategoryViewModel();
List<Categories>? categories = [];
#override
void initState() {
// categoryViewModel.fetchCategoryyListApi();
context.read<CategoryViewModel>().fetchCategoryyListApi();
// getList();
print("In filter initstate");
print(
"categoty List :${context.read<CategoryViewModel>().categoriess.length}");
getList();
super.initState();
}
getList() {
Provider.of<CategoryViewModel>(context, listen: false)
.categoriess
.map((category) {
return checkBoxes.add(CheckBoxSettings(title: category.title!));
});
print("checkBoxxxxxxxxxx: ${checkBoxes.length}");
}
**This is categoryviewModel:**
class CategoryViewModel extends ChangeNotifier {
List<Categories> categoriess = [];
final _myRepo = CategoryRepository();
Future<void> fetchCategoryyListApi() async {
_myRepo.fetchCategoryList().then((value) {
categoriess = value.categories!;
notifyListeners();
print(categoriess);
}).onError((error, stackTrace) {
print(error.toString());
});
}
}

How to use SharedPreference Globally?

I pass the value of both userProfileID And ,userstype to Profilepage() as shown below but when i go to profile page and I try to print the value of both this variable I will get Null value, I think they Actually not passed from this _HomePageState, anyone help?
Here is Where I pass the Value of both
userProfileID as a UserID and userstype as UserTypes inside initState() below,
and both UserID and UserTypes are Obtained from SharedPrefrence
(I call GetData to obtain the value of UserID and UserTypes from SharedPreference )
class _HomePageState extends State<HomePage> {
String UserID;
String UserTypes;
List<Widget>_children;
bool isSignedIn= false;
int _CurrentIndex=0;
void initState(){
super.initState();
GetData();
_children=[
TimeLinePage(UsersIdTimeline:UserID,UsersTypeTimeline:UserTypes),
SearchPage(searchUserSID: UserID,searchUsertype:UserTypes), //search(),
UploadPage(uploadUserSID:UserID,uploadUsertype: UserTypes),
NotificationsPage(NotifyUserSID: UserID,NotifyUsertype:UserTypes),
ProfilePage(userProfileID:UserID,userstype:UserTypes),
];
if(FirebaseAuth.instance.currentUser!=null){
setState(() {
isSignedIn= true;
});
}else{
setState(() {
isSignedIn= false;
});
}
}
#override
Widget build(BuildContext context) {
if(isSignedIn){
return buildHomeScreen();
} else{
return buildSignedInScreen();
}
}
void GetData()async {
SharedPreferences preferences= await SharedPreferences.getInstance();
setState(() {
UserID=preferences.get('UserId');
UserTypes=preferences.get('UserType');
});
}
}
here is buildHomeScreen
class _HomePageState extends State<HomePage> {
// ignore: non_constant_identifier_names
String UserID;
String UserTypes;
List<Widget>_children;
List<Widget>_agentchildren;
bool isSignedIn= false;
// ignore: non_constant_identifier_names
int _CurrentIndex=0;
int _agentCurrentIndex=0;
void initState(){
super.initState();
GetData();
_children=[
TimeLinePage(UsersIdTimeline:UserID,UsersTypeTimeline:UserTypes),
SearchPage(searchUserSID: UserID,searchUsertype:UserTypes),
UploadPage(uploadUserSID:UserID,uploadUsertype:UserTypes),
NotificationsPage(NotifyUserSID: UserID,NotifyUsertype:UserTypes),
ProfilePage(userProfileID:UserID,userstype:UserTypes),
];
if(FirebaseAuth.instance.currentUser!=null){
setState(() {
isSignedIn= true;
});
}else{
setState(() {
isSignedIn= false;
});
}
}
#override
Widget build(BuildContext context) {
if(isSignedIn){
if(UserTypes=='agent'){
return buildagentScreen();
} else if(UserTypes== 'Signupuser'||
UserTypes== 'owner'||
UserTypes== 'seller'
){
return buildHomeScreen();
}else{
return buildSignedInScreen();
}
}
}
Here is My ProfilePage(), if I try to get the value of both
( String userstype; String userProfileID;) in this page
i get Null value but I alredy pass the value of them from the above _HomePageState()
class ProfilePage extends StatefulWidget {
String userstype;
String userProfileID;
ProfilePage({this.userProfileID, this.userstype});
#override
_ProfilePageState createState() => _ProfilePageState();
}
class _ProfilePageState extends State<ProfilePage> {
final String CurrentOnlineUserID=curentuser?.uid;
bool loading =false;
int countPost=0;
String postOrientation="grid";
List<Post> PostList=[];
void initState(){
getAllProfilePost();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black,
appBar:header(context,strTitle:"profile"),
body:ListView(
children:<Widget>[
TopView(),
]
),
);
}
Use shared preferences globally for your application.
import 'dart:async' show Future;
import 'package:shared_preferences/shared_preferences.dart';
class PreferenceUtils {
static Future<SharedPreferences> get _instance async => _prefsInstance ??= await SharedPreferences.getInstance();
static SharedPreferences _prefsInstance;
// call this method from iniState() function of mainApp().
static Future<SharedPreferences> init() async {
_prefsInstance = await _instance;
return _prefsInstance;
}
static String getString(String key, [String defValue]) {
return _prefsInstance.getString(key) ?? defValue ?? "";
}
static Future<bool> setString(String key, String value) async {
var prefs = await _instance;
return prefs?.setString(key, value) ?? Future.value(false);
}
}
Please follow this link
https://stackoverflow.com/a/61046061/8218866
When the _HomePageState is created, the initState is called, and so this line:
_children=[
[...],
ProfilePage(userProfileID:UserID,userstype:UserTypes),
];
This line is creating the object of a ProfilePage with the desired UserID's and UserTypes. This ProfilePage object will be put inside the _children list.
When you do this:
setState(() {
UserID=preferences.get('UserId');
UserTypes=preferences.get('UserType');
});
You are 1) calling the build method again, and 2) updating the value of UserID and UserTypes. You did not change the value of any itens inside the _childrens list. Or the list itself. Hence the misbehavior you noticed.
There are many ways to solve this, but the essence would be to move this list declaration inside the build method. An example:
#override
Widget build(BuildContext context) {
_children = [.....]
if(isSignedIn){
[...]
Doing this way would not be a pretty way to do it, because you are creating lots of new (and useless) objets every time the build method is called. Maybe in a small application this wouldn't be a problem, and for didactic reasons I chose to show this way in this answer.
The more correct way would be to :
Switch and instantiate inside buildHomeScreen the body object:
Scaffold buildHomeScreen(){
Widget body;
switch (_currentIndex) {
case 0:
body =
TimeLinePage(UsersIdTimeline:UserID,UsersTypeTimeline:UserTypes);
break;
case 1:
body = ...;
break;
}
return Scaffold(
...
body: body,
...
)
}
Which should give you the same result.

how to access to variable from StatefulWidget to State class flutter

I try to pass data from page one to page two data is pass OK but I have one problem now.
this is my code:
class SecondScreen extends StatefulWidget {
final int itemHolder ;
SecondScreen({Key key, #required this.itemHolder}) : super(key: key);
#override
State<StatefulWidget> createState() {
return new mainState();
}
}
class mainState extends State <SecondScreen> {
bool value = false ;
MyPreferences _myPreferences = MyPreferences();
#override
void initState() {
// TODO: implement initState
super.initState();
initial();
}
void initial() async {
setState(() {
});
}
final String apiURL = 'http://xxxxxxxxx/getFlowersList.php';
Future<List<Flowerdata>> fetchFlowers() async {
var response = await http.get(apiURL);
if (response.statusCode == 200) {
final items = json.decode(response.body).cast<Map<String, dynamic>>();
List<Flowerdata> listOfFruits = items.map<Flowerdata>((json) {
return Flowerdata.fromJson(json);
}).toList();
return listOfFruits;
}
else {
throw Exception('Failed to load data from Server.');
}
}
I try to use var (itemHolder ) in the link like that:
final String apiURL = 'http://xxxxxxx/getFlowersList.php?id=' +itemHolder;
but I get error:
Undefined name 'itemHolder'. Try correcting the name to one that is defined, or defining the name.
I can access to itemHolder. So how can I access to it?
try this:
...
String apiURL;
#override
void initState() {
super.initState();
apiURL = 'http://xxxxxxx/getFlowersList.php?id=' +widget.itemHolder.toString();
}
...
To use the variables declared in the SecondScreen you have to access it with the prefix 'widget' and the dot operator, not directly. Here is the code:
final String apiURL = 'http://xxxxxxx/getFlowersList.php?id=' + widget.itemHolder;
And when you make the variable final, you have to initialize it while declaration or through constructor else delete keyword final:

How to ensure code is run only once in a widget?

I do have a lot of code that looks like
this:
bool _somethingFromApiLoaded = false;
Something _somethingFromApi;
loadSomething() async {
final something = await ServiceProvider.of(context).apiService.getSomething();
setState(() => _somethingFromApi = something);
}
#override
Widget build(BuildContext context) {
if (!_somethingFromApiLoaded) {
loadSomething();
_somethingFromApiLoaded = true;
}
}
Note how I produce a lot of boilerplate code to ensure loadSomething is only called once.
I wonder if there isn't a lifecycle method to do so that I somehow misinterpret. I can't use initState because it does not have context.
I would try to a use a StatefulWidget and use initState() method.
That is the lifecycle you are referring to.
You should try to use a Future inside the initState()
#override
void initState() {
super.initState(); // make sure this is called in the beggining
// your code here runs only once
Future.delayed(Duration.zero,() {
_somethingFromApi = await ServiceProvider.of(context).apiService.getSomething();
});
}
As User gegobyte said, Context is available in the initState.
But apparently can't be used for everything.
You can use context in initState() by passing it to the widget:
class HomeScreen extends StatefulWidget {
final BuildContext context;
HomeScreen(this.context);
#override
State<StatefulWidget> createState() => new _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
bool _somethingFromApiLoaded = false;
Something _somethingFromApi;
loadSomething() async {
final something = await ServiceProvider.of(widget.context).apiService.getSomething();
setState(() => _somethingFromApi = something);
}
#override
void initState() {
super.initState();
if (!_somethingFromApiLoaded) {
loadSomething();
_somethingFromApiLoaded = true;
}
}
}

How to load data from file in one stateful class and use it in another stateful class in flutter?

I am new to Flutter. I have a dart file "CreateDatabase.dart" which should fetch data from a csv file and store in a variable. In another file, "main.dart", I want to access this variable to use the fetched data.
The "CreateDatabase.dart" file looks like this:
class CreateDatabase extends StatefulWidget{
#override
State<StatefulWidget> createState() {
return CreateDatabaseState();
}
}
class CreateDatabaseState extends State<CreateDatabase> {
#override
void initState(){
super.initState();
fetchVenueDatabase();
}
List<List<dynamic>> venueDB;
List<Buildings> buildings;
List<Buildings> getBuildings(){
return this.buildings;
}
Future<String> _loadVenueDatabase() async {
return await rootBundle.loadString('assets/VenueDatabase.csv');
}
Future<List<List<dynamic>>> loadVenuedatabase() async {
String data = await _loadVenueDatabase();
List<List<dynamic>> rowsAsListOfValues = const CsvToListConverter().convert(data);
return rowsAsListOfValues;
}
fetchVenueDatabase() async{
venueDB = await loadVenuedatabase();
......
//manipulating venueDB and storing its value in this.buildings
......
this.buildings = buildings;
}
#override
Widget build(BuildContext context) {
return null;
}
}
And the main.dart file looks like this:
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return _MyAppState();
}
}
class _MyAppState extends State<MyApp> {
static List<Buildings> allBuildings;
#override
void initState() { //Initial State of the app
super.initState();
CreateDatabaseState cr = CreateDatabaseState();
allBuildings = cr.getBuildings();
}
#override
Widget build(BuildContext context) {
....
}
}
But the getter method in main,
allBuildings= cr.getBuildings();
is always returning null. Where am I wrong?
You shouldnt use a Widget for that. Just create a normal class and define your methods there.
class Database {
}
List<List<dynamic>> venueDB;
List<Buildings> buildings;
List<Buildings> getBuildings(){
return this.buildings;
}
Future<String> _loadVenueDatabase() async {
return await rootBundle.loadString('assets/VenueDatabase.csv');
}
Future<List<List<dynamic>>> loadVenuedatabase() async {
String data = await _loadVenueDatabase();
List<List<dynamic>> rowsAsListOfValues = const CsvToListConverter().convert(data);
return rowsAsListOfValues;
}
fetchVenueDatabase() async{
venueDB = await loadVenuedatabase();
......
//manipulating venueDB and storing its value in this.buildings
......
this.buildings = buildings;
}
}
Then in your main class just plain and simple.
Database db = Database();
allBuildings = db.getBuildings();
Then you need to load the venues before db.getBuildings() or do some async stuff. But this should be easy to do. One option would be to make the main() method async and await for some kind of dataLoading. You could make the venueDB List static so that it holds the data independent of the Database object.
This way you can call: Database.fetchVenueData() which then must use the static List and be of course static itself.
Future main() async {
await Database.fetchVenueData();
runApp(MyApp());
}
and the modified Database class:
static List<List<dynamic>> venueDB;
static Future<void> fetchVenueDatabase() async{
venueDB = await loadVenuedatabase();
......
//manipulating venueDB and storing its value in this.buildings
......
Database.buildings = buildings;
}
But there are many more options.
Disclaimer: I have not compiled that code. So perhaps there is a missing piece or something but you should get the idea.
Disclaimer2: static variables are kind of bad. So use them wisely. They wont get garbage collected but i assume this CSV data should reside in memory anyway as long as your app is running. If this shouldnt be the case, there are far better options.