Pass value of variables to another widget Flutter - flutter

I'm trying to pass a value of a variable from a StatefulWiget to another StatefulWidget
class InputFieldCheckTick extends StatefulWidget {
double timbreFiscaleFournisseur = 0.000;
bool exoTVA = false;
.
.
.
value: isTicked,
onChanged: (value) async {
await setState(() {
isTicked = value;
if (isTicked == false) {
widget.exoTVA = false;
} else {
widget.exoTVA = true;
}
});
.
.
.
value: isTicked,
onChanged: (value) async {
await setState(() {
isTicked = value;
if (isTicked == false) {
widget.exoTVA = false;
} else {
widget.exoTVA = true;
}
});
and i'm trying to pass the values of exoTVA and timbreFiscaleFournisseur here :
setState(() {
future = ajoutFournisseur(
numeroFournisseur.text,
addressFournisseur.text,
matriculeFiscaleFournisseur.text,
raisonSocialeFournisseur.text,
paysFournisseur.text,
villeFournisseur.text,
InputFieldCheckTick()
.timbreFiscaleFournisseur,
InputFieldCheckTick().exoTVA);
});

I think you are creating an StatefulWidget which contains a Final property called exoTVA, something like:
class MyWidget extends StatefulWidget {
final bool exoTVA;
[...]
Because you are calling widget.exoTVA which refers to stateful related widget, and there is your mistake. You can't change widget.exoTVA for the way widgets are build. What you can do is to do this:
class _MyWidgetState extends State<MyWidget> {
// Here you designate an instance value for your widget property
bool? _exoTVA;
// On initState you define from parent widget, I do this all the time
#override
initState((){
super.initState();
_exoTVA = widget.exoTVA;
});
[...] //Continue with the rest of your widget
Also when you call those changes in setState, change widget.exoTVA to _exoTVA, and to finish you can call that var like this:
setState(() {
future = ajoutFournisseur(
numeroFournisseur.text,
addressFournisseur.text,
matriculeFiscaleFournisseur.text,
raisonSocialeFournisseur.text,
paysFournisseur.text,
villeFournisseur.text,
InputFieldCheckTick()
.timbreFiscaleFournisseur,
_exoTVA);//Changed this line
});
For your reference, check out StatefulWidget class

Related

How to reach results of a function from another file (TextEditingController, ElevatedButton)

I have two files, in the first are a few TextformFields and in the second are buttons. I wanna disable the button when one of the TextformFields is empty.
File 1:
class FormTextState extends State<FormText>{
final TextEditingController inputController1 = TextEditingController();
final TextEditingController inputController2 = TextEditingController();
final TextEditingController inputController3 = TextEditingController();
bool submit1 = false;
bool submit2 = false;
bool submit3 = false;
#override
void initState(){
super.initState();
inputController1.addListener(() { setState(() {
submit1 = inputController1.text.isNotEmpty;
});
});
inputController2.addListener(() { setState(() {
submit2 = inputController2.text.isNotEmpty;
});
});
inputController3.addListener(() { setState(() {
submit3 = inputController3.text.isNotEmpty;
});
});
}
#override
void dispose(){
inputController1.dispose();
inputController2.dispose();
inputController3.dispose();
super.dispose();
[...]
}
For each TextFormField the controller is defined as following:
TextFormField(
controller: inputController1,
If I would create the button directly in this file, everything works fine like that:
ElevatedButton(
onPressed: submit1 && submit2 && submit3 ? () => doSomething() : null,
How can I reach this result from the other file with the buttons? The submit values are not reachable. I imported the file at the beginning, of course.
You could add a function to your class like:
class FormTextState extends State<FormText>{
final Function(String str) stringHandler;
...
and when creating the class
FormTextState(stringHandler: _handler);
Future<void> _handler(String str) async {
print(str);
}
you nee to use the following porperties
autovalidateMode: AutovalidateMode.onUserInteraction
onChanged: (val) {
if (formKey.currentState?.validate() == true) {
BlocProvider.of<MyDataBloc>(context)
.add(ActivateButtonEvent());
} else {
BlocProvider.of<MyDataBloc>(context)
.add(DeActivateButtonEvent());
}
},
this will work for formtextfield in case that you are using bloc

Call setState from class that extends StatefulWidget

If I update a variable using class object, the build method should get called, but I am unable to call setState from the StatefulWidget class.
class CustomErrorFormField extends StatefulWidget {
#override
_CustomErrorFormFieldState createState() {
return _CustomErrorFormFieldState();
}
List<String> errorList = []; //this variable will get updated using below function
void setErrorList(List<String> listOfError) {
errorList = listOfError;
}
}
class _CustomErrorFormFieldState extends State<CustomErrorFormField> {
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
print(widget.errorList); //this is not printing updated value
return .....
}
}
Now in some other class i will update errorList Variable
nameTextFild = CustomErrorFormField(
key: ValueKey(count),
labelName: "Name",
iContext: context,
onChanged: (String value) {
setState(() {
count++;
if (!value.contains(RegExp(r'[0-9]'))) {
nameTextFild!.setErrorList([]); //updating but changes not appearing (setState of this widget is not getting called)
} else {
nameTextFild!.setErrorList(["Invalid characters, use letters only."]);
}
});
},
);
It's not recommended that you change the state of a widget from outside the widget.
What you should do instead is pass the validation logic as a function and let the widget handle the state change.
CustomFormField:
import 'package:flutter/material.dart';
class CustomErrorFormField extends StatefulWidget {
//Take the validation logic as a parameter.
final List<String> Function(String value) validator;
const CustomErrorFormField({required this.validator});
#override
_CustomErrorFormFieldState createState() {
return _CustomErrorFormFieldState();
}
}
class _CustomErrorFormFieldState extends State<CustomErrorFormField> {
//Keep the state inside the widget itself
List<String> errorList = [];
//Update the state from inside the widget
void setErrorList(List<String> listOfError) {
setState(() {
errorList = listOfError;
});
}
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Form(
child: TextFormField(
validator: (String value){
//Use the validation logic to decide the error.
setErrorList(widget.validator(value))
}
}
),
);
}
}
I have used TextFormField as an example, you can use any widget that accepts a callback upon change.
If you're making everything from scratch you can attach the validator function to a callback that fires when the text is changed. Usually this is done with the help of a controller.
usage:
final nameTextFild = CustomErrorFormField(
key: ValueKey(count),
labelName: "Name",
iContext: context,
validator: (String value) {
if (!value.contains(RegExp(r'[0-9]'))) {
return [];
} else {
return ["Invalid characters, use letters only."];
}
},
);

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.

I want to use data from a Future inside a ChangeNotifier Provider and a ListView

I can't figure out how to get the data from the myProvider before I call the getWalletItems(). Should I do 2 seperate providers??
My goal here is just to get all these items from a Future<List<Wallet'>> and return them into a listview that is able to have each item be selectable with a checkbox which will then pass on all the selected items to a different page. They will not be rebuilt there so I don't think I need another model but if I do just let me know. Here is my code for the ChangeNotifier:
class WalletModel extends ChangeNotifier {
List<Wallet> _wallet = [];
List<Wallet> get wallet => _wallet;
set wallet(List<Wallet> newValue) {
_wallet = newValue;
notifyListeners();
}
myProvider() {
loadValue();
}
Future<void> loadValue() async {
wallet = await WalletApi.getWalletItems();
}
UnmodifiableListView<Wallet> get allWalletItems =>
UnmodifiableListView(_wallet);
UnmodifiableListView<Wallet> get incompleteTasks =>
UnmodifiableListView(_wallet.where((_wallet) => !_wallet.isSelected));
UnmodifiableListView<Wallet> get completedTasks =>
UnmodifiableListView(_wallet.where((_wallet) => _wallet.isSelected));
void toggleWallet(Wallet wallet) {
final walletIndex = _wallet.indexOf(wallet);
_wallet[walletIndex].toggleSelected();
notifyListeners();
}
}
Here is the checkbox to select
Checkbox(
value: wallet.isSelected,
onChanged: (bool? checked) {
Provider.of<WalletModel>(context, listen: false)
.toggleWallet(wallet);
},
),
Here is the listview and if I need to post anyother code just let me know because I'm quite lost on what to do.
class WalletList extends StatelessWidget {
final List<Wallet> wallets;
WalletList({required this.wallets});
#override
Widget build(BuildContext context) {
return ListView(
children: getWalletListItems(),
);
}
List<Widget> getWalletListItems() {
return wallets
.map((walletItem) => WalletListItem(wallet: walletItem))
.toList();
}
}
make myProvider() a future and then use below code for WalletList Widget
before build runs for WalletList we want to get the items from the provider so we have used didChangedDependencies() as it runs before build and can be converted to future.
when the list is got we use the list that was set by above the make the UI
Note : Consumer changes its state whenever notifyListener() is called in Provider.
import 'package:flutter/material.dart';
class WalletList extends StatefulWidget {
#override
_WalletListState createState() => _WalletListState();
}
class _WalletListState extends State<WalletList> {
bool _isInit = true;
#override
void didChangeDependencies() async {
//boolean used to run the set list fucntion only once
if (_isInit) {
//this will save the incoming data to list before build runs
await Provider.of<WalletModel>(context, listen: false).myProvider();
_isInit = false;
}
super.didChangeDependencies();
}
#override
Widget build(BuildContext context) {
return Consumer<WalletModel>(builder: (context, providerInstance, _) {
return ListView(
children: providerInstance
.wallet
.map<Widget>((walletItem) => WalletListItem(wallet: walletItem))
.toList(),
);
});
}
// List<Widget> getWalletListItems() {
// return Provider.of<WalletModel>(context, listen: false)
// .wallet
// .map((walletItem) => WalletListItem(wallet: walletItem))
// .toList();
// }
}

How to set onChanged value of Switch

I have a switch which toggle the app theme but there is some errors on the code
Switch(value: AppStyleMode.isSwitched, onChanged: (value)=> AppStyleMode.switchMode())
My Theme file
import 'package:flutter/material.dart';
class AppStyleMode extends ChangeNotifier {
bool isSwitched = true;
Color primaryBG = Colors.white;
Color appBarBG = Colors.yellow;
switchMode() {
if (isSwitched == true) {
primaryBG = Colors.black];
appBarBG = Colors.grey[400];
isSwitched = false;
} else {
//if it is dark mode currently switch to light
primaryBG = Colors.white;
appBarBG = Colors.yellow;
isSwitched = true;
}
notifyListeners();
}
}
Errors on Switch :
If you are not using any particular state management packages,
First, you would have to create an instance of your AppStyleMode class, so that you can use values from it and also listen to it's changes.
Assuming you have a StatefulWidget,
first define your AppStyleMode in it's State,
class MyState extends State<MyStatefulWidget> {
late AppStyleMode appStyleMode;
Then in your initState, initialise it and add a listener to it.
void initState () {
super.initState();
appStyleMode = AppStyleMode();
// Also add a listener to it and call setState to rebuild your StatefulWidget
appStleMode.addListener(() => {
setState(() {});
});
}
Then you can use it in your build by using your variable appStyleMode like this,
Switch(value: appStyleMode.isSwitched, onChanged: (value) => appStyleMode.switchMode())
I would rather suggest you look into a State management solution like provider or Getx. But it is not compulsory.