setting field value with a setter with field Name & value as parameter - flutter

I faced a problem while try building an application.
the problem is that trying to set the field in SomeClass with a general setField function.
my implementation was like this but faced an issue withthis[fieldName];
EDITED
class TestClass {
String name; // <- to set this the memberName = 'name';
int age; // <- to set this the memberName = 'age';
// and both will use the same setField as setter.
TestClass({required name, required age});
// the prev code is correct and no problem with it.
/** the use will be like this to set the value of name **/
/** test.setField(memberName : 'name', valueOfThatMemberName: 'test name'); // notice here **/
/** the use will be like this to set the value of age **/
/** test.setField(memberName : 'age', valueOfThatMemberName: 15); // notice here **/
void setField({required String memberName, required var valueOfThatMemberName}) {
// some extra validation and logic,..
this[memberName] = valueOfThatMemberName; // this gives this error:
/** Error: The operator '[]=' isn't defined for the class 'TestClass'. **/
}
// this will return the valueOfThePassedMemberName;
getField({required String memberName}) {
return this[memberName]; // <= this gives this error
/** Error: The getter 'memberName' isn't defined for the class 'TestClass'. **/
}
}
void main() {
TestClass test = TestClass(name: 'alaa', age: 14);
/** here is the way to use it. **/
test.setField(memberName: 'name', valueOfThePassedMemberName: 'test name'); // notice here
test.setField(memberName: 'age', valueOfThePassedMemberName: 16); // notice here
print(test.getField(memberName: 'name')); // <- this should print the name of test object.
}
setting the values just through the setField method.
ADDING RUNABLE JS CODE
// i need to do the exact same thing here with the dart.
export class Entity {
constructor(data: {}) {
Object.keys(data).forEach(key => {
this.set(key, data[key], true);
});
}
get(field: string) {
return this["_" + field];
}
set(field: string, value: any, initial = false) {
this["_" + field] = value;
}
}

class TestClass {
late String fieldName;
late dynamic value;
TestClass({required fieldName, required value});
void setField({required String fieldName, required var value}) {
// some extra validation and logic,..
this.fieldName = fieldName;
this.value = value;
}
getField() {
return fieldName;
}
getValue() {
return value;
}
}
void main() {
TestClass test = TestClass(fieldName: 'name', value: 'Alaa');
test.setField(fieldName: 'name', value: 'Alaa');
print('${test.getField()}: ${test.getValue()} ');
test.setField(fieldName: 'age', value: 14);
print('${test.getField()}: ${test.getValue()} ');
}

After a lot of researching, I found that there is no way to do it directly, but there is another way i'm gonna drive you into the steps:
1- Install the package
we need to install Reflectable
Readme
Changelog
Example
Installing
Versions
Scores
Use this package as a library
Depend on it
Run this command:
With Dart:
dart pub add reflectable
With Flutter:
flutter pub add reflectable
2- Import the package into the class
import 'package:reflectable/reflectable.dart';
3- Create the Reflectable Class
class MyReflectable extends Reflectable {
const MyReflectable() : super(invokingCapability);
}
const myReflectable = MyReflectable();
4- Add the Annotation into the class
#myReflectable
class TestClass {
late String name;
late int age;
setField({required String fieldName, value}) {
var instanceMirror = myReflectable.reflect(this);
instanceMirror.invokeSetter(fieldName, value);
}
getField({required String fieldName}) {
var instanceMirror = myReflectable.reflect(this);
return instanceMirror.invokeGetter(fieldName);
}
}
6- build main.reflectable.dart
run this line in project root folder
dart run build_runner build
7- Initialize the Refactable
import this line into the main.dart
import 'package:erp/main.reflectable.dart';
add this line into your main.
initializeReflectable();
8- Use it
TestClass test = TestClass();
test.setField(fieldName: 'name', value: 'Alaa');
test.getField(fieldName: 'name'); // <- this will return 'Alaa'
test.setField(fieldName: 'name', value: 'Ahmad');
test.getField(fieldName: 'name'); // <- this will return 'Ahmad'
// and the same for any other field.
test.setField(fieldName: 'age', value: 14);
test.getField(fieldName: 'age'); // <- this will return 14
test.setField(fieldName: 'age', value: 20);
test.getField(fieldName: 'age'); // <- this will return 20
Finally
Thanks to who contribute to try to answer and help :-)

Related

How to dynamically create object names based on a list?

I have a class FoodDetails which accepts a list of names
class FoodDetails extends StatefulWidget {
FoodDetails({this.namesList});
final List namesList;
#override
State<FoodDetails> createState() => FoodDetailsState();
}
I want to create objects of a class NameClass based on the names of namesList.
For example:
If namesList=["John", "Doe"];
I want to create lists like
List<NameClass> John;
List<NameClass> Doe;
How can I achieve this? I tried the following but it doesn't work
class FoodDetailsState extends State<FoodDetails> {
void initState() {
super.initState();
for (int i = 0; i < widget.namesList.length; i++) {
List<NameClass> widget.namesList[i];
}
}
}
You cannot create objects dynamically like javascript in dart.
Easy workaround would be using HashMap in which the key will be the desired dynamically allocated name and the value will be the instance of the object.
Code snippet which would help you start with this:
import 'dart:collection';
class Class {
String? var1;
String? var2;
Class({var1, var2}) {
this.var1 = var1;
this.var2 = var2;
}
}
void main() {
var list = ["John", "Doe"];
HashMap<String, Class> map = new HashMap();
list.forEach((element) {
map.addAll({element: new Class()}); // Just adding the key to the Map
});
print(map.containsKey("John"));
print(map.containsKey("Doe"));
// Can easily manipulate the value known the key
map["John"]!.var1 = "variable1";
map["Doe"]!.var2 = "variable2";
map.forEach((key, value) {
print("Key: " +
key +
" has values var1: " +
(value.var1 ?? "") +
" and var2: " +
(value.var2 ?? ""));
});
}
The output would be:
true
true
Key: John has values var1: variable1 and var2:
Key: Doe has values var1: and var2: variable2

class object and property variation in dart

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"
}
}

Return a class from the function in Dart

Is there any way using which I can return a Class as a function return type?
My sample code:
class Data_1{
static int price = 1;
}
class Data_2{
static int price = 2;
}
getData() {
if (widget.data_name == "Data_1"){
return Data_1;
} else if (widget.data_name == "Data_2"){
return Data_2;
}
}
void print_price() {print(getData.price);}
Using the above code getting the below error:
The getter 'price' isn't defined for the type 'dynamic Function()'.
Try importing the library that defines 'price', correcting the name to the name of an existing getter, or defining a getter or field
named 'names'.
There are a few issues with the code above, to fix them:
We should define a property getter in the classes:
class Data_1 {
static int _price = 1;
get price => _price;
}
class Data_2 {
static int _price = 2;
get price => _price;
}
getData() should return an instance of the class, not the Type:
getData() {
if (widget.data_name == "Data_1")
{return Data_1();} // not Data_1
else if (widget.data_name == "Data_2")
{return Data_2();} } // not Data_2
}
We can now call the getData() function and access the price getter:
void main() {
print(getData().price);
}
Follows the full code example:
class Data_1 {
static int _price = 1;
get price => _price;
}
class Data_2 {
static int _price = 2;
get price => _price;
}
getData() {
return Data_1();
}
void main() {
print(getData().price);
}

how to get a string for a class property name in dart?

i want to do use the model's properties such as:
Animal.id as a param to a function or use some extension method to be able to "id". similarly, i'd like to use Animal.title in that way to get "title" as a returned value. how could i do this with my class to get a string for any given property name?
int _id;
String _title;
Animal(this._id, this._title);
int get id => _id;
String get title => _title;
}
the usage case is being able to query without having autocomplete on my model's property names in a string for sql querying:
List<Map> results = await db.query("Animal",
columns: Set. ["id", "title"],
where: 'id = ?',
whereArgs: [id]);
Using the dart:mirrors package you can dynamically access your class properties and invoke methods using their string names.
https://api.dart.dev/stable/2.4.0/dart-mirrors/dart-mirrors-library.html
import 'dart:mirrors';
class Animal {
int _id;
String _title;
Animal(this._id, this._title);
int get id => _id;
String get title => _title;
}
main() {
var r = reflect(Animal(1, 'Dog'));
print(r.getField(Symbol('id')).reflectee);
print(r.getField(Symbol('title')).reflectee);
}
import 'dart:mirrors';
class MyClass {
int i, j;
void my_method() { }
int sum() => i + j;
MyClass(this.i, this.j);
static noise() => 42;
static var s;
}
main() {
MyClass myClass = new MyClass(3, 4);
InstanceMirror myClassInstanceMirror = reflect(myClass);
ClassMirror MyClassMirror = myClassInstanceMirror.type;
InstanceMirror res = myClassInstanceMirror.invoke(#sum, []);
print('sum = ${res.reflectee}');
var f = MyClassMirror.invoke(#noise, []);
print('noise = $f');
print('\nMethods:');
Iterable<DeclarationMirror> decls =
MyClassMirror.declarations.values.where(
(dm) => dm is MethodMirror && dm.isRegularMethod);
decls.forEach((MethodMirror mm) {
print(MirrorSystem.getName(mm.simpleName));
});
print('\nAll declarations:');
for (var k in MyClassMirror.declarations.keys) {
print(MirrorSystem.getName(k));
}
MyClassMirror.setField(#s, 91);
print(MyClass.s);
}
the output:
sum = 7
noise = InstanceMirror on 42
Methods:
my_method
sum
noise
All declarations:
i
j
s
my_method
sum
noise
MyClass
91

How to setup Moq with Callbacks?

Ok, I have started to look at Moq, so this is a noob question.
I have followed the quick guide, and I am trying to setup a callback to return a specific model:
void Main()
{
var resultData = new MyModel();
var mock = new Mock<IMyClass>();
mock.Setup(x => x.Register(It.IsAny<string>()))
.Returns(new MyModel { Name = "Test" })
.Callback<MyModel>((data) =>
{
resultData = data;
});
var parameter = "123";
var result = mock.Object.Register(parameter);
}
public interface IMyClass
{
MyModel Register(string code);
}
public class MyModel
{
public string Name { get; set; }
}
I get this exception on the call:
ArgumentException: Object of type 'System.String' cannot be converted
to type 'UserQuery+MyModel'.
What am I doing wrong?
The T in the Callback<T> method should match the parameter type of the method being Setup. In other words, Moq is letting you set a callback method with the same parameters as the method being mocked.
I'm not exactly sure what you're trying to do here. If you're just trying to save the return MyModel object from your mocked method, do this:
var returnedModel = new MyModel { Name = "Test" };
mock.Setup(x => x.Register(It.IsAny<string>()))
.Returns(returnedModel);
If you're trying to create a MyModel with the given string parameter, do this:
mock.Setup(x => x.Register(It.IsAny<string>()))
.Returns((string data) => new MyModel { Name = data });