I have a class named vendor
class Vendor {
int id;
String name;
Vendor({this.id , this.name});
}
Now I have another class person, in this class I have a list of vendors I want to set default value in person constructor:
class Person {
List<Vendor> vendor;
Person({this.vendor});
}
I've tried this solution but it did not work
class Person {
List<Vendor> vendor;
Person({this.vendor}) : vendor = vendor ?? const [];
}
You can set default values for optional constructor parameters using =:
class Foo {
final List<String> strings;
Foo({this.strings = const ['example']});
}
class Bar {
final List<String> strings;
Bar([this.strings = const ['example']]);
}
print(Foo().strings); // prints '[example]'
print(Bar().strings); // prints '[example]'
Note, values passed in as optional parameters must be const.
Related
Click Here to see Dartpad Screenshot
void main(){
Student file1 = Student.empty;
Student file2 = Student.empty;
file1.name = 'ABC';
file2.name = 'DEF';
print(file1.name);
print(file2.name);
}
class Student{
String name;
Student({
required this.name,
});
static Student empty = Student(name: '');
}
Output Value
DEF
DEF
Expected Value
ABC
DEF
This happens, because you are using the same static instance of Student, since the static field is shared across all instances of Student.
So your variables file1 and file2 are referencing the same single instance of Student.
You may want to use a factory constructor instead:
https://dart.dev/guides/language/language-tour#factory-constructors
void main() {
Student file1 = Student.empty();
Student file2 = Student.empty();
file1.name = 'ABC';
file2.name = 'DEF';
print(file1.name);
print(file2.name);
}
class Student {
String name;
Student({
required this.name,
});
factory Student.empty() {
return Student(name: '');
}
}
so i recently started learning dart and I've found something kinda interesting.
why do we use constructors and getters/setters when we can achieve same results without them? (atleast when used for basic things).
class v1{
var name;
int age;
v1(this.name, this.age);
info(){
print("my name is $name and i am $age");
}
}
class v2{
var name = "bash";
int age = 100;
info(){
print("my name is $name and i am $age");
}
}
class v3{
var namee;
int agee;
String get name => namee;
int get age => agee;
set name(String name) => this.namee = name;
set age(int age) => this.agee = age;
info(){
print("my name is $name and i am $age");
}
}
void main(){
var x = v1("bash", 100);
x.info(); //my name is bash am i am 100
var z = v2();
var Z = v2();
Z.name = "vert";
Z.age = 20;
z.info(); //my name is bash and i am 100
Z.info(); //my name is vert and i am 100
var y = v3();
y.name = "rizz";
y.age = 40;
y.info(); //my name is rizz and i am 40
}
Here's a more correct version of your class:
class User {
final bool _isMale;
String _name;
int _age;
User(this._isMale, this._name, this._age);
bool isMale => _isMale;
String get name => _name;
int get age => _age;
set name(String name) {
// Sometimes you may want to update other properties here.
// For example:
// _isUpdated = true;
_name = name;
}
set age(int age) {
_age = age;
}
void info() {
print("my name is $name and i am $age");
}
}
Constructors are useful when you want to assign initial values to the class fields. They are essential if you need to assign final fields, as they are assignable only on class initialization (see _isMale field).
Setters are useful when you want to update other fields along with the field that's being modified.
Getters protect the internal state from being modified outside. In this example, nobody can change _isMale field.
You don't need to use getters and setters unless you have to.
You use getters and setters if you need to store the data in a private field, or if you want to modify it when saving or returning the value.
class Abc {
String _field;
String _otherField;
String anotherField; // No getters and setters required for this.
String get field => _field;
set field(String field) => _field = field;
String get otherField => "The value of otherField is: " + _otherField;
set otherField(String otherField) => _otherField = "[String] " + otherField;
}
As for constructors, you use them to initialize the object with custom values. When you need to work with immutable objects (which use final variables), you'll have to use constructors to set their initial value. You can also modify the incoming value according to your need before storing it,
class Def {
final field; // Dart generates getters for this field, but it's value can't be modified once the object is instantiated.
final _otherField; // No getters for this.
Def(String field, String otherField) {
this.field = "[String] $field"
this._otherField = "[String] $otherField"
}
String describeMe() {
return "[Def]: field: $field, _otherField: $_otherField"
}
}
I am new to Flutter, and trying to declare a Folder class with one of the properties being a list of children Folders. I am not able to arrive to a correct declaration, the language gives me various errors. Someone can help me out with that?
class Folder {
final int id;
final String title;
final List<Folder> children;
Folder ({
this.id = 0,
this.title = '',
this.children
});
factory Folder.fromJson(Map<String, dynamic> parsedJson) {
Iterable i = parsedJson['children'];
return new Folder(
id: parsedJson['id'] ?? '',
title: parsedJson['title'] ?? '',
children: List<Folder>.from(i.map((model) => Folder.fromJson(model)))
);
}
}
This gives me for the children property the following error: The parameter 'children' can't have a value of 'null' because of its type, but the implicit default value is 'null'.
Sometimes the Folder doesn't have subfolders, so I wouldn't like to create a #required parameter, just an optional.
I guess you're using the latest version of Dart with the null-safety enabled ?
If that's the case, declaring your children var this way
List<Folder>? children;
should do the trick.
Another solution would be to update your constructor
Folder ({
this.id = 0,
this.title = '',
this.children = []
});
I cannot set a default value this.<List>propertyName = [] in the parameter because the value needs to be const. So I went with not declaring a default value and created a setter/getter.
Here's my example:
[batches.dart]
class Batches{
String? _batchName;
List<Trainees>? _trainees;
// Constructor
Batches({batchName, trainees}) {
this.batchName = batchName;
this.trainees = trainees;
}
// Getter Setter
String? get batchName => this._batchName;
set batchName(String? batchName) => this._batchName = batchName;
List<Trainees>? get trainees => this._trainees;
set trainees(List<Trainees>? traineeList) {
this._trainees = traineeList;
print("Added list of trainees to $batchName!");
}
}
Called the setter function in void main() and then set the existing List batch1_trainees to the setter of the function
[main.dart]
List<Trainees> batch1_trainees = [
Trainee("Trainee Wan"),
Trainee("Trainee Tiu"),
];
Batches batch1 = Batches(batchName: "first_batch");
batch1.trainees = batch1_trainees;
`
Trainees is a class that takes Full_Name as a positional parameter.
If the setter is called, the console should print Added list of trainees to first_batch!
PS.
The getter and setter were necessary in my example because the properties were set to private.
I am modelling a Dart class with the new null safety types in mind. I believe there are two effective ways to initialize non-nullable properties, calculated from a parameter.
For this example, we will use the Favourite class.
This class uses the initializer list in the constructor.
class Favourite {
int favouriteId;
Favourite({required this.favouriteId});
Favourite.mapFromJson(dynamic json)
: this.favouriteId = json["favouriteId"];
}
This class uses the 'late' keyword.
class Favourite {
late int favouriteId;
Favourite({required this.favouriteId});
Favourite.mapFromJson(dynamic json) {
this.favouriteId = json["favouriteId"];
}
}
When would you use one over the other? Using 'late' feels risky. If I added another named constructor, the compiler would not complain about 'favouriteId' not being initialized.
Are there other options?
Thank you!
Neither.
Use a default constructor that initializes the fields themselves and a factory constructor that handles deserializing the json object:
class Favourite {
final int favouriteId;
Favourite({required this.favouriteId});
factory Favourite.fromMap(Map<String, dynamic> map) {
final favouriteId = json['favouriteId'];
assert(favouriteId != null && favouriteId is int);
return Favourite(
favouriteId: favouriteId,
);
}
}
The late keyword can be a source of headache if you don't handle it properly, so in general don't use it unless you have to.
If you're sure the json will always have a "favouriteId", you can write it like this:
class Favourite {
int favouriteId;
Favourite({required this.favouriteId});
Favourite.mapFromJson(Map<String, dynamic?> json):
assert(() {
final favouriteId = json["favouriteId"];
return favouriteId != null && favouriteId is int;
}()),
favouriteId = json["favouriteId"] as int;
}
void main() {
dynamic m = {"favouriteId":2};
final favourite = Favourite.mapFromJson(m);
print("favourite id: ${favourite.favouriteId}");
}
I was wondering if I can check which constructor I used to create the created element in an if statement in dart.
A simple example of what I want to do:
class Employee {
int id;
String name;
String title;
Employee.id(this.id);
Employee.name(this.name);
Employee.title(this.title);
}
Now I have an if statement somewhere in my code and want to check if I used the constructor Employee.id. In this case I would do something, somehow like this:
Employee e = new Employee.id(1)
//check if e was created with Employee.id constructur
if (e == Emploee.id) {
print(e.id)
} else {
print("no id")
}
Is there a way to do this? Thank you for your answer.
You can make your class a Union type using the freezed package and use the folding methods as shown below to see what constructor was used:
import 'package:freezed_annotation/freezed_annotation.dart';
part 'tst.freezed.dart';
#freezed
abstract class Employee with _$Employee {
const factory Employee.id(int id) = IdEmployee;
const factory Employee.name(String name) = NameEmployee;
const factory Employee.title(String title) = TitleEmployee;
}
void main() {
Employee employee1 = Employee.id(0);
Employee employee2 = Employee.name('some name');
Employee employee3 = Employee.title('some title');
employee1.when(
id: (int id) => print('created using id contsrutor and id= $id'),
name: (String name) => print('created using name const and name = $name'),
title: (String title)=>print('created using title const and title = $title'),
);//prints the first statement
employee2.when(
id: (int id) => print('created using id contsrutor and id= $id'),
name: (String name) => print('created using name const and name = $name'),
title: (String title)=>print('created using title const and title = $title'),
);//prints the second statement
employee3.when(
id: (int id) => print('created using id contsrutor and id= $id'),
name: (String name) => print('created using name const and name = $name'),
title: (String title)=>print('created using title const and title = $title'),
);//prints the third statement
print(employee1 is IdEmployee);
print(employee1 is NameEmployee);
}
and the output will be:
created using id contsrutor and id= 0
created using name const and name = some name
created using title const and title = some title
true
false
You can define private enum property for you to set private info like this, and print it with a function later on. Also don't forget to mark your constructors with factory.
enum _ConstructorType {
Identifier,
Name,
Title,
}
class Employee {
int id;
String name;
String title;
_ConstructorType _constructorType;
factory Employee.id(id) {
return Employee._privateConstructor(_ConstructorType.Identifier, id: id);
}
factory Employee.name(name) {
return Employee._privateConstructor(_ConstructorType.Name, name: name);
}
factory Employee.title(title) {
return Employee._privateConstructor(_ConstructorType.Title, title: title);
}
Employee._privateConstructor(this._constructorType,
{this.id, this.name, this.title});
String constructorDescription() {
return this._constructorType.toString();
}
}
If you need this information not as a string, but as enum, you can always remove underscore on it, and make this info public for you to use outside of the class.