How do I access an variable from a StatefulWidget inside an StatelessWidget? - flutter

How do I access the variable "selectedTag" from this statefulWidget:
class _AlertDialogOneState extends State<AlertDialogOne> {
Item selectedTag;
...
}
}
inside this statelessWidget :
class CardTile extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(...

Pass it as parameter,
class CardTile extends StatelessWidget {
final Item selectedTag;// Add this
CardTile(this.selectedTag); // Add this
#override
Widget build(BuildContext context) {
return Container(...

To pass this variable, you have multiple ways:
Pass it as a constructor when u navigate to this class using your navigator
Navigator.push(
context,
MaterialPageRoute(builder: (context) => CardTile(selectedTag)),
);
class CardTile extends StatelessWidget {
Item selectedTag;
CardTile(this.selectedTag);
#override
Widget build(BuildContext context) {
return Container(...
Use a state management like provider
class ProviderData with ChangeNotifier {
Item selected;
void changeSelection(newSelect) {
selected = newSelect;
changeNotifier();
}
}
and inside any class you need call this:
final providerData = Provider.of<ProviderData>(context);
so you can access the variable or change it using this instance like this:
final variable = providerData.selected;
providerData.changeSelection(newValue);
print(variable);
hope this help but i see that it is better to pass it through the constructor if you are not using a state managemnt, however i just gave you an example for illustration

Related

How to move a variable outside build?

How do I move a variable that uses a context outside of the build method so that it is created once?
class _EventListState extends State<EventList> {
#override
Widget build(BuildContext context) {
final eventNotifier = EventInherited.of(context).eventNotifier;
...
You can use the late modifier.
class _EventListState extends State<EventList> {
late final eventNotifier = EventInherited.of(context).eventNotifier;
#override
Widget build(BuildContext context) {
...
make
eventNotifier
class variable and connect it to the getter function.
class _EventListState extends State<EventList> {
var? eventNotifier;
#override
Widget build(BuildContext context) {
eventNotifier = EventInherited.of(context).eventNotifier;
}
Dynamic get getEventNotifier => this.eventNotifier;
You can use the didChangeDependencies() method. The context is available at that point.
#override
void didChangeDependencies(){
super.didChangeDependencies();
final eventNotifier = EventInherited.of(context).eventNotifier;
}
This method will be called again in certain scenarios, so be careful about what you are initializing.
This thread has more information on when it is recalled, but in general it is okay to use for initialing listeners.
Understanding Flutter didChangeDependencies mechanics

Flutter Class Properties (basics)

How do you pass properties to a widget class in flutter.
Here is a basic class
class ToolbarToggle extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Text(label);
}}
I want to be able to call it
ToolbarToggle(label: 'a label')
Forgive the elementary question.
First you declare a label property, like this:
class ToolbarToggle extends StatelessWidget {
final String label;
#override
Widget build(BuildContext context) {
return Text(label);
}
}
final means the value is immutable, you should add it to every property on a StatelessWidget.
Now we need to declare a Constructor, here is how we do that:
ToolbarToggle(this.label);
This means that when creating a ToolbarToggle, we can do this: ToolbarToggle('some label');. In order to make parameters named, we need to declare the constructor like so:
ToolbarToggle({this.label});
Now it is possible to call ToolbarToggle(label: 'my label');. But this will give an error, because it's possible you don't actually pass any value when calling the constructor. To fix this, you should either make it a required parameter, or give it a default value:
ToolbarToggle({required this.label});
ToolbarToggle({this.label=''});
Here is the final class code:
class ToolbarToggle extends StatelessWidget {
ToolbarToggle({required this.label});
final String label;
#override
Widget build(BuildContext context) {
return Text(label);
}
}
class ToolbarToggle extends StatelessWidget {
final String? label;
const ToolbarToggle({this.label, Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Text(label ?? 'label is null');
}}
Like this, you can pass properties,
Its recommended to use const constructor and a key param ( to uniquely identify incase)
You missed using the label
class ToolbarToggle extends StatelessWidget {
final String label;
ToolbarToggle({required this.label});
#override
Widget build(BuildContext context) {
return Text(label);
}}

Flutter getx controller get the current page context

I would like to use context to show a custom dialog from cool alert in getxcontroller method.
I have created the following controller
class HomePageController extends GetxController {
#override
void onInit() {
super.onInit();
getData();
}
void getData(){
//perform http request here
//show cool alert
CoolAlert.show(
context: context, //here needs the build context
type: CoolAlertType.success
);
}
}
Am using this controller in my stateless widget like
class HomePage extends StatelessWidget {
HomePage({ Key? key }) : super(key: key);
final _c = Get.find<HomePageController>();
#override
Widget build(BuildContext context) {
return Container(
);
}
}
How can i get the current homepage BuildContext in the controller inorder to show the cool alert.
If you want to show a dialog or snackbar what need context as a required agument. You can use Get.dialog() and Get.snackbar, there function work same as showDialog and showSnackbar but *without* context or scaffod
you can add the context to the construct function:
#override
Widget build(BuildContext context) {
Get.put(HomePageController(context: context));
return Container();
}
and for the HomePageController:
note: you need to wrap the function with Future.delayed(Duration.zero)
otherwise it will throw an error
class HomePageController extends GetxController {
late BuildContext context;
HomePageController({required this.context});
void getData(){
Future.delayed(Duration.zero,(){
CoolAlert.show(
context: context, //here needs the build context
type: CoolAlertType.success
);
});
}
...
}
You Need to Initialize the controller on the homepage like following
class HomePage extends StatelessWidget {
HomePage({ Key? key }) : super(key: key);
final _c = Get.put(HomePageController())..getData(context);
#override
Widget build(BuildContext context) {
return Container(
);
}
}
This will call getData Function and remove the onInit Function and Pass Buildcontext context parameter in getData Function.

How to use ever() with Flutter getx variable in GetxController if I didn't add .obs

I am using Flutter getx package.
I know how to use "ever" with (.obs) variable like this
class CountController extends GetxController {
final count = 0.obs;
#override
void onInit() {
ever(count1, (_) => print("$_ has been changed"));
super.onInit();
}
}
But how to use "ever()" or triggering specific callbacks when variable change if the variable doesn't have (.obs) because I am using GetBuilder (not : Obx or GetX) in my view
class AnyScreen extends StatelessWidget {
final controller = Get.put(CounterController());
#override
Widget build(BuildContext context) {
ever(controller.counter, (value) => print("$value has been changed"));
}
#override
Widget build(BuildContext context) {
return Text("whatever!");
}
}
NOTE: Workers should always be used when starting a Controller or Class, so it should always be on onInit (recommended), Class constructor, or the initState of a StatefulWidget (this practice is not recommended in most cases, but it shouldn't have any side effects)
docs

Best way to pass data from a root to deeper child widget in Flutter

I am new to flutter. My flutter widget tree is getting deeper and deeper, I want to know which is the best method to pass data from a root to a widget which is much deeper from it. I'm currently passing it as a constructor from widget to widget.
My current implementation is given below
Level1(data: data)
Level2(data: data)
Level3(data: data)
Level4(data: data)
suppose my data is retrieved from DB in level1 widget and it is used in level4 widget. As we see, my current implementation is considerably messy. How this is generally done? what is the best practice?
You might like to use Provider. You can find more about it here.
Basically, you create provider of the data at the top-most level like:
class Level1 {
#override
Widget build(BuildContext context) {
Provider<Data>(
create: (_) => Something(),
child: Level2 (
// stuff of level 2
),
),
}
}
Something in this case bight be a change notifier.
You can then access it at a lower level with:
final provider = Provider.of<Something>(context);
Inherited widget - If you want to avoid using any third party library..
More can be found here - https://medium.com/#mehmetf_71205/inheriting-widgets-b7ac56dbbeb1
and here https://www.youtube.com/watch?v=Zbm3hjPjQMk
class MyInheritedWidget extends InheritedWidget {
final int accountId;
final int scopeId;
MyInheritedWidget(accountId, scopeId, child): super(child);
#override
bool updateShouldNotify(MyInheritedWidget old) =>
accountId != old.accountId || scopeId != old.scopeId;
}
class MyPage extends StatelessWidget {
final int accountId;
final int scopeId;
MyPage(this.accountId, this.scopeId);
Widget build(BuildContext context) {
return new MyInheritedWidget(
accountId,
scopeId,
const MyWidget(),
);
}
}
class MyWidget extends StatelessWidget {
const MyWidget();
Widget build(BuildContext context) {
// somewhere down the line
const MyOtherWidget();
...
}
}
class MyOtherWidget extends StatelessWidget {
const MyOtherWidget();
Widget build(BuildContext context) {
final myInheritedWidget = MyInheritedWidget.of(context);
print(myInheritedWidget.scopeId);
print(myInheritedWidget.accountId);
...