Flutter pass User instance to another state and keep it updated - dart

I am trying to make a login/registration process and redirect user to a Dashboard view.
So I have this method:
Future _redirectToDashboard() async {
var route = new MaterialPageRoute(
builder: (BuildContext context) => new Dashboard(userID: userID),
);
Navigator.of(context).push(route);
}
And then call it after login() is finished.
_register().whenComplete(() => _redirectToDashboard());
And then in Dashboard I do this:
class Dashboard extends StatefulWidget
{
int userID;
Dashboard({Key key, this.userID}) : super(key: key);
#override
_Dashboard createState() => _DashboardState();
}
And use it with:
Text('User ID: ${widget.userID}')
But then I cannot do this in Dashboard class:
Dashboard({Key key, this.userID, this.name, this.balance}) : super(key: key);
even though I set it in a function above as:
builder: (BuildContext context) => new Dashboard(userID: userID, name: name, balance: balance),
But it doesn't work. I get an error that name for example is not defined Why can I only pass one parameter? And is there a way how can I update the Dashboard with new data every time user opens this state?
I read that I should create a seperate User class with all properties. But how can I apply it to a dashboard?

I assume you only added constructor parameters, without adding the actual class members.
class Dashboard extends StatefulWidget
{
final int userID;
final String name;
final String balance;
Dashboard({Key key, this.userID, this.name, this.balance}) : super(key: key);
#override
_Dashboard createState() => _DashboardState();
}

Related

Generic parameter type in Dart? [duplicate]

This question already has an answer here:
Why am I getting TypeError at runtime with my generic StatefulWidget class?
(1 answer)
Closed 10 months ago.
I'm trying to create a class that use a generic type as a parameter in a callback that returns some subtype of Flutter's Widget. Here's what I started with:
class Subscriber<P extends PublishingController> extends StatefulWidget {
const Subscriber({required this.builder, Key? key}) : super(key: key);
final Widget Function(P) builder;
#override
_SubscriberState<P> createState() => _SubscriberState<P>();
}
class _SubscriberState<P extends PublishingController> extends State<Subscriber> {
final P publisher = GetIt.instance.get<P>();
#override
void initState() {
publisher.subscribe(rebuild);
super.initState();
}
#override
Widget build(BuildContext context) {
return widget.builder(publisher);
}
#override
void dispose() {
publisher.unsubscribe(rebuild);
super.dispose();
}
void rebuild() {
setState(() {});
}
}
... with the Publisher:
mixin Publisher {
List<Function> subscribers = <void Function()>[];
void subscribe(Function f) {
subscribers.add(f);
}
void unsubscribe(Function f) {
subscribers.remove(f);
}
void publish() {
for (var f in subscribers) {
f();
}
}
}
class PublishingController with Publisher {}
... and how I called it:
child: Subscriber<MapController>(
builder: (controller) => Column(...
... with:
class MapController extends PublishingController {...
... but that gives me the error:
======== Exception caught by widgets library =======================================================
The following _TypeError was thrown building Subscriber<MapController>(dirty, state: _SubscriberState<MapController>#d7e05):
type '(MapController) => Column' is not a subtype of type '(PublishingController) => Widget'
I think I'm specifying the parameter type through the generics, and a function can return a subtype of its return type— what am I getting wrong here?
EDIT:
I got it working, but I'm not putting this in as an answer— I don't understand what the problem was, or why this version works; I changed my Subscriber class to:
abstract class Builder<P extends PublishingController> extends StatefulWidget {
const Builder({required this.builder, Key? key}) : super(key: key);
final Widget Function(P) builder;
}
class Subscriber<P extends PublishingController> extends Builder<P> {
const Subscriber({required builder, Key? key}) : super(builder: builder, key: key);
#override
_SubscriberState<P> createState() => _SubscriberState<P>();
}
Can someone explain why this change would make the difference?
Your _SubscriberState<P> class extends State<Subscriber>, which in your case is shorthand for State<Subscriber<PublishingController>>, not for State<Subscriber<P>>.
The static type of the _SubscriberState<P>'s inherited widget member therefore will be Subscriber<PublishingController>, and the static type of widget.builder will be Widget Function(PublishingController). At runtime, the associated Subscriber object has a reference to a Column Function(MapController) object. However, that cannot be treated as a Widget Function(PublishingController) since it does not accept all PublishingController arguments, so you end up with a runtime error.
See: Why am I getting TypeError at runtime with my generic StatefulWidget class?

default values in dart constructor

I have the following class which has required unpressedImage field. I need to set unpressedImage value to pressedImage field if pressedImage is not specified. How can I achieve this the best way?
class ImageButton extends StatefulWidget {
final Image unpressedImage;
final Image pressedImage;
final onTap;
const ImageButton({
Key key,
#required this.unpressedImage,
this.pressedImage,
this.onTap,
}) : super(key: key);
#override
_ImageButtonState createState() => _ImageButtonState();
}
Set it in the initialization list, and use a conditional to pick which value you want to use:
class ImageButton extends StatefulWidget {
final Image unpressedImage;
final Image pressedImage;
final onTap;
const ImageButton({
Key key,
#required this.unpressedImage,
Image pressedImage,
this.onTap,
}) : this.pressedImage =
pressedImage == null ? unpressedImage : pressedImage,
super(key: key);
#override
_ImageButtonState createState() => _ImageButtonState();
}

How can i get the user input as the URL for another screen?

I'm trying to obtain the user input from the first page and then pass to the second page to call the API. However it returns that 'only static members can be accessed in initializers'. Can anyone help?
my code is as following
String trackingnum = _trackingnumController.text;
Navigator.push(context, MaterialPageRoute(builder: (context)=>new
TrackingPage(trackingnum2: trackingnum)))
another screen
class TrackingPage extends StatefulWidget {
final String trackingnum2;
TrackingPage({Key key, #required this.trackingnum2}) : super(key: key);
#override
TrackingPageState createState() => TrackingPageState();
}
class TrackingPageState extends State<TrackingPage> {
final url = urL + "/${widget.trackingnum2}";

Flutter and Firestore: How can access variables from Stateful Widget to create a new document?

i want to use a final variable from a StatefulWidget inside a StatelessWidget to create a new document in Firestore.
But i get always the same issue: Only static members can be accessed in initializers
My StatefulWidget Code:
class UserProfile extends StatefulWidget {
UserProfile({this.auth, this.onSignedOut, this.userID});
final BaseAuth auth;
final VoidCallback onSignedOut;
final String userID;
#override
_UserProfileState createState() => new _UserProfileState();
}
My StatelessWidget Code:
class _UserProfilState extends State<UserProfile> {
final DocumentReference userdocuments =
Firestore.instance.collection("Users").document(widget.userID); //Here i get the Error, because widget.userID
}
My Question: How can i use the the userID Variable from the StatefulWidget, to create a new document based on the userID. Thanks for our help
You can get the value in the initState method
class _UserProfilState extends State<UserProfile> {
DocumentReference userdocuments;
#override
void initState() {
userdocuments =
Firestore.instance.collection("Users").document(widget.userID);
super.initState();
}
}

Why does Flutter State object require a Widget?

The demo example has the following code, which is apparently typical of Flutter apps:
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {...}
}
I'm OK, I guess, with MyHomePage overriding the StatefulWidget createState method. It's a little awkward but what the heck? And even depending on a State subclass. Fine.
But then having the State subclass turn around and depend on MyHomePage?! I'm having trouble wrapping my fairly abundant wits around that one.
So perhaps I'm unclear on what State<MyHomePage> is/does. With, say, Map<String, Object> the meaning is clear: Associate a string with an object. Can someone please elucidate? And if you could include something about the need for a state object to extend a widget, I would enjoy reading that.
This is to make widget properties access far easier.
When you do
new MyStatefulWidget(foo: 42, bar: "string")
Then you most likely want to access foo/bar from your State.
Without such syntax you'd have to type custom State constructor and pass all StatefulWidget subclass properties to State subclass inside createState. Basically you'd have that:
class MyStatefulWidget extends StatefulWidget {
final int foo;
MyStatefulWidget({this.foo});
#override
MyStatefulWidgetState createState() => MyStatefulWidgetState(foo: foo);
}
class MyStatefulWidgetState extends State<MyStatefulWidget> {
final int foo;
MyStatefulWidgetState({this.foo});
#override
Widget build(BuildContext context) {
return Container(
);
}
}
Boring. You have to write all fields of StatefulWidget subclass twice.
With the current syntax; you don't have to do this. You can directly access all properties of the currently instantiated widget within State by using widget field.
class MyStatefulWidgetState extends State<MyStatefulWidget> {
#override
Widget build(BuildContext context) {
print(widget.foo);
return Container();
}
}
In Flutter, everything is a widget and there are 2 types of widgets: Stateless and Statefull.
Stateless: A widget that does not require mutable state.
Statefull: A widget that has mutable state.
That is why all Statefull widget is dependent of a State<T>, because it manages changes (state) in the widget.

Resources