I'm having a hard-time understanding the structure of dart objects. Can someone explain what is the rightway to structure dart objects?
In the first code snippet, the constructor is called before the initiation of the variables with a final tag.
class _VideoDescription extends StatelessWidget {
const _VideoDescription({
Key key,
this.title,
this.user,
this.viewCount,
}) : super(key: key);
final String title;
final String user;
final int viewCount;
...
}
While in the second snippet, I am getting an error when I place the variable initiation after the constructor and give it a type of final. Hence this structure.
class Category {
String imgUrl;
String name;
Category(name, imgUrl) {
this.imgUrl = imgUrl;
this.name = name;
}
}
Another thing, what is the use of : super(key: key); at the end of the constructor on the first snippet?
From the docs:
By default, a constructor in a subclass calls the superclass’s unnamed, no-argument constructor. The superclass’s constructor is called at the beginning of the constructor body. If an initializer list is also being used, it executes before the superclass is called. In summary, the order of execution is as follows:
initializer list
superclass’s no-arg constructor
main class’s no-arg constructor
Regarding final variables you can do the following two ways:
class Category {
final String imgUrl;
final String name;
Category(this.imgUrl,this.name);
}
or:
class Category {
final String imgUrl;
final String name;
Category(imgUrl,name)
: imgUrl = imgUrl,
name = name;
}
Basically the final variables need to be initialized before the constructor body is executed, since the final variable cannot change.
Regarding the super check the following:
void main() {
var students = Students(1, "peter");
print(students.name);
}
class Students extends Person {
final int id;
Students(id, age)
: id = id,
super(age) {
print("I'm the constructor body");
}
}
class Person {
final String name;
Person(name) : name = name {
print("I'm the super constructor");
}
}
This will print:
I'm the super constructor
I'm the constructor body
peter
So here since you have final variables then you need to create an initializer list to initialize these variables and since Students extends Person and since the super class Person doesnt have a no-argument constructor, then you must call super(age). The order of execution will be the same as explained above.
Related
I'm using json_serializable's JSONConverter interface to convert Firestore's DocumentReferences into valid JSON objects.
This is the JSON converter class. It tries to be generic:
class DocumentSerializer<T>
implements JsonConverter<DocumentReference<T>, DocumentReference<T>> {
const DocumentSerializer();
#override
DocumentReference<T> fromJson(DocumentReference<T> docRef) => docRef;
#override
DocumentReference<T> toJson(DocumentReference<T> docRef) => docRef;
}
And this is the usage of the annotation:
#JsonSerializable(explicitToJson: true)
class Recipe {
#DocumentSerializer<Recipe>()
final DocumentReference<Recipe> id;
#DocumentSerializer<User>()
final DocumentReference<User> authorId;
final String title;
final String description;
final String imageUrl;
final List<DocumentReference<User>> likes;
final List<String> ingredients;
final List<String> steps;
.
.
.
}
Unfortunately, this does not work. The build runner fails when it reaches the first usage of the annotation, which is the id field. Is there a way to provide generics to DocumentReferences in JsonConverter which can be serialized properly?
I found a workaround; albeit less elegant than what I'm aiming for. Turns out separate JsonConverters need to be created for each DocumentReference type.
For example, if I have an id field of type DocumentReference<Recipe> for the Recipe class , I would need to create the following JSON converter...
class RecipeSerializer
implements
JsonConverter<DocumentReference<Recipe>, DocumentReference<Recipe>> {
const RecipeSerializer();
#override
DocumentReference<Recipe> fromJson(DocumentReference<Recipe> json) => json;
#override
DocumentReference<Recipe> toJson(DocumentReference<Recipe> object) => object;
}
...and use it as such:
#JsonSerializable(explicitToJson: true)
class Recipe {
#RecipeSerializer()
final DocumentReference<Recipe> id;
#UserSerializer() // <- same goes for other types
final DocumentReference<User> authorId;
final String title;
final String description;
final String imageUrl;
final List<DocumentReference<User>> likes;
final List<String> ingredients;
final List<String> steps;
.
.
.
}
A bit more verbose, but I'll take it unless someone comes up with a more efficient answer.
I am trying to understand, how can I use the bloc pattern (specifically state) properly. I am facing this issue for more than a month, but not able to figure out a solution.
Let's consider, I have defined state class following way,
#freezed
abstract class ExampleState with _$ExampleState {
const factory ExampleState.initial() = Initial;
const factory ExampleState.getDataFromServer() = GetDataFromServer; //Thsi will return the ServerData Object.
const factory ExampleState.useServerData() = UseServerData;
const factory ExampleState.changeServerDataAndUpload() = ChangeServerDataAndUpload;
}
Let's consider our Server Data Model is the following way
class ServerData {
final String userId;
final String firstName;
final String lastName;
final String fullAddress;
final String fatherName;
ServerData(
this.userId,
this.firstName,
this.lastName,
this.fullAddress,
this.fatherName,
);
}
In this example, we are able to see, GetDataFromServer, UseServerData, and ChangeServerDataAndUpload state is sharing the same ServerData object. How should I design my state such that, the same DataModel object can be shared between different states?
I am creating a program that needs to use Provider to get values. I call my provider like below in a stateful widget
final user = Provider.of<Users>(context);
Now I would like to use the provider in a custom class
class UserInformation {
final user = Provider.of<Users>(context):
}
This won't work because context is not defined. kindly assist on how I can do this without using a BuildContext.
This is my class Users that I have on a separate dart file and use as a model for for my data streams.
class Users {
final String uid;
final String name;
final String department;
final String position;
Users({ this.uid, this.department, this.name, this.position });
}
This is the query I use to pull data from firestore
Stream<List<FormQuestions>> get userData{
return userCollection.where('name', isEqualTo: 'First Name').where('department', isEqualTo: 'department').snapshots()
.map(_userDataFromSnapshot);
}
I would like the name to be a variable that I get from say (user.name) from the model class. and the same for the department.
Thanks.
You can only access classes which are ChangeNotifiers in the descendant widgets in the tree below this provided ChangeNotifier because behind the scenes the Provider uses InheritedWidget (which uses context) to provide you with the ChangeNotifier you put up in the tree
So in your case there is no way to access the Users from UserInformation and you have to alter your code to make a workaround
Edit: this is a suggestion to achieve what you want if you are using this code inside a widget:
class UserInformation{
final User user;
UserInformation(this.user);
}
class SomeWidget extends StatefulWidget {
#override
_SomeWidgetState createState() => _SomeWidgetState();
}
class _SomeWidgetState extends State<SomeWidget> {
void someMethod(){
final User user = Provider.of<Users>(context);
UserInformation userInformation = UserInformation(user);
//do something
}
#override
Widget build(BuildContext context) {
return Container();
}
}
¡Hey! In the class you need to add "with ChangeNotifier":
class Users with ChangeNotifier {
final String uid;
final String name;
final String department;
final String position;
Users({ this.uid, this.department, this.name, this.position });
}
Hope help. Sorry for the english, yo hablo español. :D
I am passing variables from one activity to another in flutter but getting the error "Instance member ‘latitude’ can’t be accessed using static access" I need it converted in that block so I can assign it to a static URL.
class Xsecond extends StatefulWidget {
final double latitude;
final double longitude;
Xsecond(this.latitude, this.longitude, {Key key}): super(key: key);
#override
_Xsecond createState() => _Xsecond();
}
class _Xsecond extends State<Xsecond> {
static String lat = Xsecond.latitude.toString(); // Error: Instance member ‘latitude’ can’t be accessed using static access
...
followed by
...
String url = 'https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=${lat},$lng&radius=$radius&type=restaurant&key=$api';
...
In your code both latitude and longitude are defined as non-static i.e. are instance variables. Which means they can only be called using a class instance.
class _Xsecond extends State<Xsecond> {
final xsecond = Xsecond();
static String lat = xsecond.latitude.toString();
...
Please read the basics of any Object Oriented Programming language e.g. Dart, java, C++
However, in your context the first class is your StatefullWidget. So you can access that by the widget field of your state class.
FIX:
class _Xsecond extends State<Xsecond> {
static String lat = widget.latitude.toString();
...
This error occurs if you use non-static variable like static. Let's take a look at this example:
class MyPage extends StatefulWidget {
final foo = Foo();
// ...
}
class _MyPageState extends State<MyPage> {
final newFoo = MyPage.foo; // Error
// ...
}
MyPage.foo isn't a static member but you are using if it was.
To solve this issue, you can either make the variable static
static final foo = Foo();
or
Use widget variable to get hold of the underlying variable.
class _MyPageState extends State<MyPage> {
#override
void initState() {
super.initState();
final newFoo = widget.foo; // No Error
}
// ...
}
I have a final and I am trying initializing that in the constructor. It is giving me error & If I don't make it final I get a warning.
This class (or a class which this class inherits from) is marked as '#immutable', but one or more of its instance fields are not final: GenderCard.genderSvg",
My Code:
GenderCard({#required this.genderType}) {
genderSvg = '/assets/' + 'genderType' + '.svg';
}
final String genderType;
final String genderSvg;
#override
Widget build(BuildContext context) {
final instance variables must be initialized in the initializer list. See the language guide.
Instance variables can be final but not const. Final instance
variables must be initialized before the constructor body starts — at
the variable declaration, by a constructor parameter, or in the
constructor’s initializer list.
Change your constructor to:
class GenderCard {
GenderCard({#required this.genderType})
: genderSvg = '/assets/$genderType.svg';
final String genderType;
final String genderSvg;
}