class Profile {
final String firstName;
final String lastName;
final session = getIt<Session>();
Profile({
this.firstName = session.profile.firstName,
this.lastName = session.profile.lastName
});
}
This code has error says
The default value of an optional parameter must be constant
So how can I initialize class that has optional parameter and default value from other instance?
Try to use the initialization list or the member initializer instead of initializing the attributes inside the constructor
For example:
class Profile {
final String? firstName;
final String? lastName;
final session = getIt<Session>();
Profile({
this.firstName,
this.lastName,
})
: firstName = firstName ?? session.profile.firstName,
lastName = lastName ?? session.profile.lastName;
}
Related
Hi I'm new to dart and flutter and I want to create a method that update multiple fields at once.
For example, suppose there is a class named User, and it looks like this:
class User {
int id;
String password;
String firstName;
String lastName;
String nickName;
String gender;
DateTime birthday;
String phoneNumber;
String address;
...
}
In this example, an instance of User will have a lot of fields and it's awkward to update multiple fields if you don't intend to update all of them.
So, when you update only password, nickName, phoneNumber and address, instead of reassigning a new User instance like this:
user = User(
id : 0,
password : 'xxxxxxx',
firstName : 'Hanako',
lastName : 'Tanaka',
nickName : 'Tanako',
gender : 'female',
birthday : DateTime(2000, 1, 1),
phoneNumber : 'xxxxxxxxxxx',
address : 'xxxxxxxxxxx'
);
I want to update them like this:
user.updateUser({
password : 'xxxxxx',
nickName : 'Tanako',
phoneNumber : 'xxxxxxxxxxx',
address : 'xxxxxxxxxxx'
});
Please tell me if there is a way to create a method that update multiple fields at once like this.
Thanks,
you can do this like this
class User {
int id;
String password;
String firstName;
String lastName;
String nickName;
String gender;
DateTime birthday;
String phoneNumber;
String address;
User({
required this.id,
required this.password,
required this.firstName,
required this.lastName,
required this.nickName,
required this.gender,
required this.birthday,
required this.phoneNumber,
required this.address,
});
updateUser({
int? id,
String? password,
String? firstName,
String? lastName,
String? nickName,
String? gender,
DateTime? birthday,
String? phoneNumber,
String? address,
}) {
this.id = id ?? this.id;
this.password = password ?? this.password;
this.firstName = firstName ?? this.firstName;
this.lastName = lastName ?? this.lastName;
this.nickName = nickName ?? this.nickName;
this.gender = gender ?? this.gender;
this.birthday = birthday ?? this.birthday;
this.phoneNumber = phoneNumber ?? this.phoneNumber;
this.address = address ?? this.address;
}
}
when you don't give a property name it will not update that field of the object for example if you want to update only firstName and lastName you can do it like this
user.updateUser(firstName:"Nao",lastName:"COMATSU");
and all other fields will not be updated
I have a class with the following attributes in Dart
class StartValue {
final int id;
final String firstName;
final String lastName;
StartValue({this.id, this.firstName, this.lastName})
}
and Ill initiate that classe with the values:
StartValue(
id: 1,
firstName: 'First',
lastName: 'LastName'
)
The question is what kind of validation i need to do to never instance a class StartValue with the NAME = 'First' again? Assuming I can only instantiate the class once with firstName = 'First'.
How do I do an instance validation to verify that each instance does not contain the firstName = "First" ?
I have to do something like:
StartValues.contains("First")
Keep in mind that I have almost 1000 classes instantiated, so I will have to check one by one if the value "First" contains in each class, this is my question
You have to iterate through every class to check if the firstName is taken, but I recommend using the == operator instead of .contains(). Why would you have 1000 instances? Can you put us in context?
Use a class-static Set of all ids seen so far. This will be quick to identify whether an item has already been generated.
Something like:
class Person {
final int id;
final String name;
static var seenIds = <int>{};
Person({
required this.id,
required this.name,
}) {
if (!seenIds.add(id)) throw ArgumentError('id $id already seen');
}
}
Keeping thousands of instances / names in memory is bad design as they are way too many instances / names you don't need at that moment. You go for local sql database like sqflite or you go for cloud database like Cloud Firestore to fetch the user you need and validate it.
If you still want to do it in-memory you can use a factory constructor, a private constructor and a static HashSet to check user instances.
If you need explanation then comment below. Full code example:
import 'dart:collection';
class Person {
final int id;
final String firstName;
final String lastName;
static HashSet<String> allNames = HashSet<String>();
factory Person({
required int id,
required String firstName,
required String lastName,
}) {
if (!allNames.add(firstName)) {
throw ArgumentError("Person with firstname $firstName already exists");
}
return Person._(id: id, firstName: firstName, lastName: lastName);
}
Person._({
required this.id,
required this.firstName,
required this.lastName
});
}
I write this class
class Profile {
String email;
String password;
Profile({this.email, this.password});
}
But it said that
"The parameter 'email' can't have a value of 'null' because of its type, but the implicit default value is 'null'.
Try adding either an explicit non-'null' default value or the 'required' modifier.dartmissing_default_value_for_parameter"
By adding required:
class Profile {
String email;
String password;
Profile({
required this.email,
required this.password,
});
}
By adding optional:
class Profile {
String? email;
String? password;
Profile({
this.email,
this.password,
});
}
By adding default values:
class Profile {
String email;
String password;
Profile({
this.email = "mail#gmail.com",
this.password = "123",
});
}
You have to make them accept a null value.
class Profile {
String? email;
String? password;
Profile({this.email, this.password});
}
I am trying to pass a few basic strings to a User Model and then on set the strings are trimmed, but my issue is if I make the passed variables to User #required and using the usual way of using set and get give me the error " Named optional parameters can't start with an underscore"
class User {
String id;
String lastName;
String email;
String _firstName;
String get firstName => _firstName;
set firstName(String name) => _firstName = name.trim();
User({#required this.id,
#required this._firstName, // Error thrown here
#required this.lastName,
#required this.email});
}
If I do the following I get static analysis errors on the set and get variables saying The declaration '_firstName' isn't referenced. Try removing the declaration of '_firstName'
class User {
String id;
String lastName;
String email;
String firstName;
String get _firstName => firstName; // Static analysis error here
set _firstName(String name) => _firstName = name.trim(); // Static analysis error here
User({#required this.id,
#required this.firstName,
#required this.lastName,
#required this.email});
}
Am I using get and set wrong? Is there a better way to do this?
EDIT : In my opinion, in your case, there is no need to use getters and setters (see documentation :
class User {
String id;
String lastName;
String email;
String firstName;
User({
#required this.id,
#required this.firstName,
#required this.lastName,
#required this.email,
}) {
firstName = firstName.trim();
}
}
Usage :
final user = User(
id: '1',
firstName: 'John',
lastName: 'Doe',
email: 'john#doe.com',
);
// set firstName :
user.firstName = 'Jane';
// get firstName :
print(user.firstName);
With getters and setters you expose a way to either get/set a value to local/private object.
Something like,
String get firstname => _firstName;
set firstName => _firstName = name.trim();
From the code you've shown, if all you're trying to do, is return a trimmed value, you can do that with only getter. Your code in that case might look as follows.
class User {
String id;
String email;
final String name;
String get firstName => name.trim();
String get lastName => name.trimLeft(); //some other calculation
User({#required this.id,
#required this.name,
#required this.email});
}
I am using json_serializable, json_annotation, and build to generate serialization/deserialization functionality for my models. When I run the build though, I get this error.
Error running JsonSerializableGenerator
Cannot populate the required constructor argument: created.
package:explorer/models/Account/account.dart:46:3
The line it is referring to is my model constructor which is this.
Account(String id, String firstName, String lastName, String email,
DateTime dob, DateTime created, DateTime updated,
{String accessTkn, String refreshTkn}) {}
Why am I getting this error?
As requested, here is my model class.
import "package:json_annotation/json_annotation.dart";
part "account.g.dart";
#JsonSerializable(nullable: true)
class Account {
#JsonKey(name: "id")
String _id;
#JsonKey(name: "first_name")
String _firstName;
#JsonKey(name: "last_name")
String _lastName;
#JsonKey(name: "email")
String _email;
#JsonKey(
name: "dob", fromJson: _isoStringToDateTime, toJson: _dateTimeToIsoString)
DateTime _dob;
#JsonKey(
name: "created",
fromJson: _isoStringToDateTime,
toJson: _dateTimeToIsoString)
DateTime _created;
#JsonKey(
name: "updated",
fromJson: _isoStringToDateTime,
toJson: _dateTimeToIsoString)
DateTime _updated;
#JsonKey(name: "access_token")
String _accessToken;
#JsonKey(name: "refresh_token")
String _refreshToken;
Account(String id, String firstName, String lastName, String email,
DateTime dob, DateTime created, DateTime updated,
{String accessTkn, String refreshTkn}) {
this._id = id;
this._firstName = firstName;
this._lastName = lastName;
this._email = email;
this._dob = dob;
this._created = created;
this._updated = updated;
this._accessToken = accessToken;
this._refreshToken = refreshTkn;
}
factory Account.fromJson(Map<String, dynamic> json) {
_$AccountFromJson(json);
}
// converts a DateTime to a ISO string
static String _dateTimeToIsoString(DateTime date) {
return date.toIso8601String();
}
// convert back to date time
static DateTime _isoStringToDateTime(String iso) {
return DateTime.parse(iso);
}
/// get the account id
String get id {
return this._id;
}
/// get the account first name
String get firstName {
return this._firstName;
}
/// get the account last name
String get lastName {
return this._lastName;
}
/// get the account email.
String get email {
return this._email;
}
/// get the account owner's date of birth
DateTime get dob {
return this._dob;
}
/// Get the date the account was created.
DateTime get createdAt {
return this._created;
}
/// get teh date the account was last updated.
DateTime get updatedAt {
return this._updated;
}
// get the account access token.
String get accessToken {
return this._accessToken;
}
// get the account refresh token.
String get refreshToken {
return this._refreshToken;
}
/// clones the account instance
Account clone() {
return Account(this.id, this.firstName, this.lastName, this.email, this.dob,
this.createdAt, this.updatedAt,
accessTkn: this.accessToken, refreshTkn: this.refreshToken);
}
Map<String, dynamic> toJson() {
_$AccountToJson(this);
}
}
You are getting the error because you didn't initialize passed parameters, you have an empty constructor.
You have to initialize every parameter you have in your class, or allow them to be nullable with JsonSerializable(nullable: true) or JsonKey(nullable: true)
Please share all code in your class if that solution wouldn't work for you
EDIT:
The library works with reflection, I understand where was an error.
Attributes should be named the same as your parameters.
Your getters should be named the same as your parameters
Change your code with next fixes:
Account(String id, String firstName, String lastName, String email,
DateTime dob, DateTime created, DateTime updated,
String accessToken, String refreshToken) {
this._id = id;
this._firstName = firstName;
this._lastName = lastName;
this._email = email;
this._dob = dob;
this._created = created;
this._updated = updated;
this._accessToken = accessToken;
this._refreshToken = refreshToken;
}
/// Get the date the account was created.
DateTime get created {
return this._created;
}
/// get teh date the account was last updated.
DateTime get updated {
return this._updated;
}
For future reference, I would like to explain the problem above with an example and suggest a general solution for it:
json_serializable + json_annotation use the constructor parameter names as the json field keys. So there is a distinct difference between the two examples below:
#JsonSerializable()
class User {
#JsonKey(name: "first_name") final String firstName;
// In this case, the json key becomes 'first_name',
// extracted from the explicitly referenced field annotation.
const User(this.firstName);
}
#JsonSerializable()
class User {
#JsonKey(name: "first_name") String _firstName;
String get firstName => _firstName?.trim();
// In this case, the json key becomes 'firstName',
// extracted from the constructor parameter name.
// For reflection, the field and its annotation are not involved.
User(String firstName) {
this._firstName = firstName;
}
}
The reason we want to hide a field is twofold; We don't want others to be able to update its value, and we want to provide a 'corrected' (in this case, trimmed) value rather than the unvalidated value retrieved from an external source. Since we are unable to neatly hide the unvalidated value, I'd suggest we do expose it but explicitly mention its shortcomings, like so:
#JsonSerializable()
class User {
// The field is final, so its value cannot be altered as if private.
// It is exposed (sadly), but clearly mentions potential issues.
#JsonKey(name: "first_name") final String firstNameUntrimmed;
// This is the 'corrected' version available with a more pleasant field name.
String get firstName => firstNameUntrimmed?.trim();
const User(this.firstNameUntrimmed);
}