I use dart 2.13.3 . In my flutter app I can't initialized Set variable without required annotation.I want to build constructor without final Set<V>initialSelectedValues;
or without required, because from another call this parameter is just optional. But show error and suggest me to add required annotation at the front of final Set<V>initialSelectedValues;. How to I change and solve this error?
class MultiSelectDialog<V> extends StatefulWidget {
MultiSelectDialog({required this.items,this.initialSelectedValues});
final List<MultiSelectDialogItem<V>> items;
final Set<V>initialSelectedValues;
#override
State<StatefulWidget> createState() => _MultiSelectDialogState<V>();
}
final selectedValues = await showDialog<Set<int>>(
context: context,
builder: (BuildContext context) {
return MultiSelectDialog(
items: items,
//initialSelectedValues: [1,2].toSet(),
);
},
);
Now, I can solve this. Change to default parameter with const .
MultiSelectDialog({required this.items,this.initialSelectedValues = const {}});
final List<MultiSelectDialogItem<V>> items;
final Set<V> initialSelectedValues;
Every final variable must have a value, if you want to set them through the constructor you have to put "required" in front of every parameter.
MultiSelectDialog({
required this.items,
required this.initialSelectedValues });
Related
I wrote this code to get access to my global scope more comfortable.
extension DepContextExtension on BuildContext {
IGlobalDependency get global => read<IGlobalDependency>();
}
I had this code to use my global dependensy
final globalScope = context.read<IGlobalDependency>();
I change it to this
final globalScope = context.global();
but i got error, that method global isn't defined for the type BuildContext. What i did wrong and how i can fix this issue?
I get globalSopce inside WidgetModel Factory from library Elementary
MainAppScreenWidgetModel mainAppScreenWidgetModelFactory(BuildContext context) {
final globalScope = context.global();
return MainAppScreenWidgetModel(
MainAppScreenModel(
globalScope.baseBloc,
),
);
}
this factory i put inside my Widget like this
class MainAppScreenWidget extends ElementaryWidget<MainAppScreenWidgetModel> {
const MainAppScreenWidget({
Key? key,
WidgetModelFactory wmFactory = mainAppScreenWidgetModelFactory,
}) : super(key: key, wmFactory);
You've declared a property so to access it just use its name:
final globalScope = context.global;
In my use case, I have to change the layout of the app with JSON data. I have a JSON file which I want to get and use the key values without using the Future method in the next method rather I want to place the mapped JSON and place it in empty curly brackets:
This is the JSON file I grab:
# test_json.json
{
"fontSize" : "10",
"fontFamily" : "A",
"fontWeigth" : "bold",
"fontColor" : "blue"
}
This is the file that grabs the JSON file and maps it:
# get_json.dart
class GetJson{
Future<Map<String, dynamic>> getJson() async {
String jsonData =
await rootBundle.loadString('assets/json/test_json.json');
Map<String, dynamic> data = jsonDecode(jsonData);
return data;
}
}
Then I grab this mapped JSON and I want to place it inside a variable called mappedData and place it inside empty curly brackets. Then I want to get the number with getNumber() and inside this method I convert the type of fontSize from string to double with another custom method called TypeConvertor.getDouble():
class Utility {
var mappedData= {};
setJson() async {
mappedData = await GetJson().getJson();
}
getNumber(String key) {
var data = mappedData;
return TypeConvertor.getDouble(data[key]);
}
}
In my use case, i need to do this like this I have no other choice. I want to explicitly grab the JSON like that and I don't want getNumber() to be a Future. Then i cannot place Utility().getNumber("fontSize") inside a stateful widget because then I have to use setState and I want to avoid that because I will have a lot of keys beside fontSize and so then I have to use setState for every key values. I just want to use Utility().getNumber("fontSize") inside property fontSize and The rest also like this. In my usecase I have to do it like that:
class TestView extends StatefulWidget {
const TestView({Key? key}) : super(key: key);
#override
State<TestView> createState() => _TestViewState();
}
class _TestViewState extends State<TestView> {
#override
Widget build(BuildContext context) {
return Text(
"test",
style: TextStyle(fontSize: Utility().getNumber("fontSize")),
);
}
}
But in my app mappedData gives null. The full error is : Unhandled Exception: type 'Null' is not a subtype of type 'String' and the null value is inside mappedData. I want to grab the json data and place it inside an empty map and use the mapped json from there on. How do i resolve the null execption issue?
EDIT
Change variables to correct versions
Probably it's because you don't call setJson before call getNumber.
The following code is work.
final utility = Utility();
await utility.setJson();
print(utility.getNumber("fontSize"));
If you want to avoid similar mistakes, you have some options as solutions.
Include mappedData to Utility's constructor.
Change getNumber to static, and add argument mappedData.
Use JsonSerializable(It's a little difficult but the best solution.)
I found the solution which is partly contributed by #bakatsuyuki. So i did use await utility.setJson(); but i also initilized it with initState() so field utility has no null value. I also used FutureBuilder() to check if snapshot.hasData and then i display the Text() widget with the data from utilitiy else show empty Container. This way i can resolve the null Exception.
This is the view that worked for me:
class AppView extends StatefulWidget {
const AppView({
Key? key,
}) : super(key: key);
#override
_AppViewState createState() => _AppViewState();
}
class _AppViewState extends State<AppView> {
final utility = Utility();
Future setUtility() async {
await utility.setJson();
}
#override
void initState() {
setUtility();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: FutureBuilder(
future: AppContent().getAppContent(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return Text("test",
style: TextStyle(
fontSize: utility.getNumber("fontSize"),
));
} else {
return Container();
}
}),
),
);
}
}
I have this Provider in my code. its suppose to return list
class ServingProvider extends ChangeNotifier {
List<Serving> servings = [];
getServings() {
Firestore.instance
.collection('servings')
.getDocuments()
.then((value) => value.documents)
.then((value) =>
value.map((serving) => Serving.fromJson(serving.data)).toList())
.then((value) => servings.addAll(value))
.then((value) => notifyListeners());
print(servings);
}
// List<Serving> get servings => servings;
}
I want to get the value here but I'm getting null for some reason.
class KMultiScrollWheel extends StatelessWidget {
final String title;
final String value;
final BuildContext passedContext;
final String dialogTitle;
KMultiScrollWheel({
#required this.title,
this.value,
#required this.passedContext,
this.dialogTitle,
});
#override
Widget build(BuildContext context) {
final servings = Provider.of<ServingProvider>(context).servings;
print(servings)
This is the wrapper of my class.
ChangeNotifierProvider(
create: (_) => ServingProvider(),
child: KMultiScrollWheel(
title: 'Serving Size',
passedContext: context,
dialogTitle: 'Select Serving',
),
),
I'm coming from react and I'm completely lost for something that should be rather simple. thanks in advance.
One last question whats the point of using get method when I can access the servings already declared at the top.
As you are using realtime database, use StreamProvider instead of ChangeNotifierProvider , this medium article can help you out
I am new to this and can't comment since I am not sure if this will work, but I don't see you calling the getServings method, so maybe your list isn't filled yet?
You could try something like this:
final servingsProvider = Provider.of<ServingProvider>(context);
(await) servingsProvider.getServings(); //and make getServings() async since it connects to Firebase
print(servingsProvider.servings);
Of course you should handle this in a future or streambuilder, to render it.
I think getServings is a Future function, so you must handle the case when servings is null. You can simply add getServings in the constructor of ServingProvider:
class ServingProvider extends ChangeNotifier {
ServingProvider(){
// call getServings in constructor, notify listener when servings update
getServings();
}
...
and handle null case of servings in KMultiScrollWheel build by your own.
The other ways are FutureProvider (set initialData when data is not ready) or StreamProvider.
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
I'm making a login page in a flutter app which requires a constructor that takes too parameters ( goToWelcomeListener, enterAnimation ) as shown:
abstract class GoToWelcomeListener {
void onGoToWelcomeTap();
}
class LoginScreen extends StatefulWidget {
final GoToWelcomeListener goToWelcomeListener;
final LoginEnterAnimation enterAnimation;
LoginScreen(
{#required AnimationController controller,
#required this.goToWelcomeListener})
: this.enterAnimation = new LoginEnterAnimation(controller);
State<StatefulWidget> createState() {
return new LoginScreenState();
}
}
class LoginScreenState extends State<LoginScreen> {
final GoToWelcomeListener goToWelcomeListener;
final LoginEnterAnimation enterAnimation;
final userNameController = TextEditingController();
final passwordController = TextEditingController();
final formKey = GlobalKey<FormState>();
final URL = "https://gam3ity.com/";
LoginScreenState(
{#required AnimationController controller,
#required this.goToWelcomeListener})
: this.enterAnimation = new LoginEnterAnimation(controller);
And as you can see i had to define the constructor two times for it to work and not give me errors, because if i defined it just in the state itself and not the class, it doesn't recognize it as a constructor, and if i declared it in the class without the state, i can't use any of the parameters in the state cuz it's initialized in the class not the state.
Then when i call the constructor in another file as shown:
"/LoginScreen": (BuildContext context) => LoginScreen()
Those are the warnings it gives me:
warning: The parameter 'controller' is required. (missing_required_param at
[gam3ity_aa] lib\main.dart:30)
warning: The parameter 'goToWelcomeListener' is required.
(missing_required_param at [gam3ity_aa] lib\main.dart:30)
warning: The parameter 'goToWelcomeListener' is required.
(missing_required_param at [gam3ity_aa] lib\screens\login\login_page.dart:34)
warning: The parameter 'controller' is required. (missing_required_param at
[gam3ity_aa] lib\screens\login\login_page.dart:34)
What am i missing?
Because of this! You marked that AnimationController and goToWelcomeListener are required params. But you just called LoginScreen() -> missing required params
LoginScreen(
{#required AnimationController controller,
#required this.goToWelcomeListener})
: this.enterAnimation = new LoginEnterAnimation(controller);