How to pass data from one screen to the drawer? - flutter

I have one screen and I want to pass data from that screen to the drawer. My drawer class looks like this:
class InitDrawer extends StatelessWidget {
final Auth auth;
InitDrawer({this.auth});
#override
Widget build(BuildContext context) {
final String _name = auth.name;
final String _email = auth.email;
final drawerHeader = UserAccountsDrawerHeader(
accountName: Text(_name),
accountEmail: Text(_email),
currentAccountPicture: CircleAvatar(
...
),
);
return ListView(
children: <Widget>[
...
],
);
}
}
This is my screen class which is passing the data
class QRScannerScreen extends StatefulWidget {
static const routeName = '/qr';
final Auth auth;
const QRScannerScreen(this.auth);
#override
_QRScannerScreenState createState() => _QRScannerScreenState();
}
class _QRScannerScreenState extends State<QRScannerScreen> {
final auth = widget.auth;
...
drawer: InitDrawer(auth: auth,),
...
}
And finally this is my Auth class/notified listener
class Auth with ChangeNotifier {
String _token;
DateTime _expiryDate;
String _userId;
int _carId;
String _email;
String _name;
String get name {
return _name;
}
String get email {
return _email;
}
...
}
I think the whole problem comes from that the auth is null and when I try to view the drawer I am getting an error saying that my widget of type Text can not contain a text which is null. Because I am getting the auth with await and async maybe the data it is not getting there in time when screen loads and it is resulting in null. Maybe I have to use setState, but I am new to Flutter/Dart and I don't know where to use it.

Try to remove final auth = widget.auth; and use widget.auth inside build method, or at least define final auth in initState method. But if you decide to use initState approach, keep in mind that you might need to update auth value inside your state class in didUpdateWidget

Related

Is there anyway I could pass an async funtion as a parameter to a constructor

I am trying to assign an async function to an instance variable.
I have tried:
class TextBox extends StatefulWidget {
late String message;
late bool isPass;
late Function(String?) callback;
TextBox(String message, bool isPass, Future<dynamic> Function(String?) async func) {
this.message = message;
this.isPass = isPass;
this.callback = func;
}
}
But get the following exception:
Expected to find ')'
I know why I get the error. I just dont know the proper syntax to do this in dart.
You can use this line of code:
final Future<void> callback;
You can change the void type to any data type you want.
You do not need to use the keyword async because making the function return a Future is enough.
Also, you can write a constructor without a body.
class TextBox extends StatefulWidget {
final String message;
final bool isPass;
final Future<dynamic> Function(String?) callback;
TextBox(this.message, this.isPass, this.callback);
...
import 'package:flutter/material.dart';
class MyHomePage extends StatefulWidget {
late String message;
late bool isPass;
late Future<String> data;
MyHomePage(this.message, this.isPass, this.data);
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String getData = '';
#override
MyHomePage get widget => super.widget;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('$getData Test Demo'),
),
body: Container(),
);
}
getFutureData() async {
getData = await widget.data;
setState(() {});
}
}
Achieve like this have used String you can use your custom class

Flutter - How to parse array items in custom widget?

I want to map my data in a custom widget, but I am not sure how to parse them in that widget.
Here is a type of data:
Here is Widget who need to serve that data:
The problem is how to prepare a custom widget in the constructor class? And how to display data in a tree? e.g this.module['title], or object notation this.module.title :)
Help!
I am a newbie in Flutter.
Thanks!
First create a class to handle your data.
class Module {
String title;
int id;
String excerpt; // I'm not sure about types... Since i can't see the values
String thumbnail;
String content;
Module.fromJson(data){
this.title = data["title"];
this.id = data["id"];
this.excerpt = data["excerpt"];
this.thumbnail = data["thumbnail"];
this.content = data["content"];
}
}
Then you use it where you fetch your data (obviously in onInit()).
List<Module> modules = List.empty();
yourMethode(){
YourApi.route().then((result){
setState((){
modules = result.map((module){return Module.fromJson(module);});
});
});
}
}
Then in your custom widget
class ModuleList extends StatelessWidget{
final List<Module> modules;
/// The constructor
const ModuleList(this.modules);
#override
Widget build(BuildContext context) {
return ListView.builder(itemBuilder: (BuildContext context, int index) {
Module myModule = modules[index];
return Column(
children: [
Text(myModule.title)
// other elements here
],
);
});
}
}
Finally use the widget in the same widget you made your API cals
//...
child: ModuleList(modules)
//...

Migrate ChangeNotifier from provider to hooks_riverpod

I want to move my entire project from provider to riverpod. But I’m stuck at this point.
class EditQuestionScreen extends StatelessWidget {
EditQuestionScreen({this.question, this.answers});
final QuestionModel question;
final List<AnswerModel> answers;
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (context) => QuestionProvider(
question: this.question,
answers: this.answers),
child: Container());
}
}
This is my provider widget for subwidgets. It's initialized only once. How can I write this class as a HookWidget with riverpod?
Quick note - with Provider or Riverpod, you don't really want/need to name the thing you are providing thingProvider. You aren't providing a provider, you're providing a thing if that makes sense.
I did my best to fill in the gaps for the rest of the code you didn't provide, so hopefully, this will help:
class QuestionModel {
QuestionModel(this.id);
final int id;
}
class AnswerModel {
AnswerModel(this.id);
final int id;
}
class QuestionWithAnswers {
QuestionWithAnswers(this.question, this.answers);
final QuestionModel question;
final List<AnswerModel> answers;
}
class QuestionAnswerNotifier extends ChangeNotifier {
QuestionAnswerNotifier(this.qwa);
final QuestionWithAnswers qwa;
QuestionModel get question => qwa.question;
List<AnswerModel> get answers => qwa.answers;
addAnswer(AnswerModel answer) {
qwa.answers.add(answer);
notifyListeners();
}
}
final questionProvider =
ChangeNotifierProvider.family<QuestionAnswerNotifier, QuestionWithAnswers>(
(ref, qwa) => QuestionAnswerNotifier(qwa));
class EditQuestionScreen extends HookWidget {
EditQuestionScreen({
#required QuestionModel question,
#required List<AnswerModel> answers,
Key key,
}) : qwa = QuestionWithAnswers(question, answers),
super(key: key);
final QuestionWithAnswers qwa;
#override
Widget build(BuildContext context) {
final provider = useProvider(questionProvider(qwa));
// Use data from provider to render your UI, for example:
return Container(
child: Column(
children: <Widget>[
Text('${provider.question}\n${provider.answers}'),
RaisedButton(
onPressed: () => provider.addAnswer(AnswerModel(5)),
child: Icon(Icons.add),
)
],
),
);
}
}
There are a few things to note here.
In Riverpod, family is how we pass parameters to providers.
QuestionWithAnswers class bundles the models you want to pass to the provider through the extra parameter provided by family.
The provider's name is suffixed with Provider, rather than the thing it is providing being named as such.
We are providing the ChangeNotifier, so that is what is returned when called useProvider.

How to get id from StatefulWidget in State?

I want to load comments in my post here. For that I need to send post id to my HTTP get request. post id I sent from another page. but I want to assign that String id; value to final response = await http.get("http://$ip:$apiPort/solutions/$id"); here id in Flutter.
How can I do that?
to clear what I want
my code is
class Solutions extends StatefulWidget {
String id ;
final bool isEditMode;
Solutions({
this.id,
this.isEditMode,
});
#override
_SolutionsState createState() => _SolutionsState();
}
class _SolutionsState extends State<Solutions> {
List data;
var ip = Configuration.yourIp;
var apiPort = Configuration.yourApiPort;
Future<List> getData() async {
final response = await http.get("http://$ip:$apiPort/solutions/$id");
return json.decode(response.body);
}
#override
void initState() {
super.initState();
this.getData();
}
#override
Widget build(BuildContext context) {
return Scaffold(
Future<List> getData() async {
final response = await http.get("http://$ip:$apiPort/solutions/${widget.id}");
return json.decode(response.body);
}
This should to the trick.
From the State class (_SolutionState in your case), you can access the widget (Solution in your case) members by finding them in widget.
BONUS
Your id should be final, since StatefulWidget is marked as an immutable class, which means its members should all be final. You have surely a warning about this from your IDE.

Passing Variables Between Two Classes in Flutter

I am making register and login pages in flutter and facing a problem as I want to use the same variables 'email' and 'password' declared inside class _MyHomePage in main.dart file
to another class SignupPage in signup.dart file.
I already imported the files but I can not use the values in both classes
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
String _email = '';
String _password = '';
final formKey = new GlobalKey<FormState>();
FormType _formType = FormType.login;
bool validateAndSave() {
final form = formKey.currentState;
if (form.validate()) {
form.save();
return true;
// print('Form is Valid Email: $_email, Password: $_password');
}
return false;
}
You can pass the data when you navigate your screen in following way.
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SignUp(email: emailvariable,pass: passvariable),
),
in following way you can receive data
class SignUp extends StatefulWidget {
final email;
final pass;
SignUp({Key key,this.email,this.pass}) : super(key: key);
#override
_SignUpState createState() => _SignUpState();
}
now in state widget you can access email and pass variable as
widget.pass and widget.email
There are two approaches for that
Pass values through class constructor
If you don't want to go back and forth you can use this
Just in the second page use like this
class Register extends StatefulWidget {
Register({Key key, this.email, this.pass});
final String email;
final String pass;
#override
_RegisterState createState() => _RegisterState();
}
class _RegisterState extends State<Register> {
#override
Widget build(BuildContext context) {
print(widget.email);
print(widget.pass);
// to use state class values you need to use the widget as the parent class object
return Container(
);
}
}
To pass the values in constructor
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Register(email: email, pass: pass),
),
Store the values in global scope before routing to another page
If you have to route multiple times and even require these values further, you store the values in global file before routing to another page and access there
Make one file
global.dart
library my_project.global;
// set default values for the initial run
String email = '';
String pass = '';
To access the values
import 'global.dart' as global;
main() {
// import the global.dart file to access the variables across the application
global.email = 'xyz#email.com';
print(global.email);
}
If the other answers do not solve your issue, you can use the InheritedModel widget that's provided by Flutter. It allows you to share data between deeply nested widgets. The documentation is good and there's even a video from the Flutter team explaining how to use it: https://api.flutter.dev/flutter/widgets/InheritedModel-class.html