Passing the attribute of a list element as a method parameter

Asked

Viewed 49 times

0

There is the possibility to pass the attribute of an element/object of a list as a function parameter and use it to return the values?

  static Future<List<dynamic>> filterElementsInList(
      {required String query, required String elementAttribute, required List<dynamic> list}) async {
    if (query.isEmpty) {
      return list;
    } else {
      return list.where((entity) {
        
        return entity.elementAttribute.contains(query);
      }).toList();
    }
  }
  • I don’t understand exactly what you’re trying to do. Your question is how to use a string (like elementAttribute in your example) to access a property dynamically, that’s it?

  • Exact. Imagine the value passed to the parameter elementAttribute is name. This would be the property actually sought in the element.

  • As far as I understand, it is possible to do this using reflect in Dart, but the same is not possible in Flutter (I imagine it is for this purpose that you are using). Please describe the situation further, depending on the case you may use reflect, or you will have to implement an interface ToMap objects that will be used in this function, or perhaps it is not necessary/feasible to do so.

  • It will be used in a Flutter application, however I am putting this code in a separate library package pure Dart. This is the reason why you want to receive the property as a parameter and access it dynamically in the object since I do not know beforehand what parameters the object/element of the list will have.

1 answer

1


What you’re asking won’t be possible.

Even if you create the code in a separate lib in pure Dart, this lib will have to be compiled in the Flutter project. The runtimes Dart script and Flutter are different, one is converted to Javascript and runs on Nodejs, and the other is converted to code native to Android or iPhone, as a result there are some features that are unique to certain runtimes, and the reflect is one of them.

What you can do will give you more work, but it’s something you’ve already expected from Dart projects: create the methods toJSON in their classes to turn them into a Map<String, dynamic>, such a method is a standard used to convert your objects into a string in format JSON.

Example

Here I will take advantage to declare an abstract class with this method to be able to use this contract later:

abstract class JsonSerializable {
  Map<String, dynamic> toJSON();
}

class User implements JsonSerializable {
  String name;
  String email;
  User({ required this.name, required this.email });

  @override
  Map<String, dynamic> toJSON() {
    return {'name': name, 'email': email};
  }
}

Having this method implemented, we can convert the object into an instance of Map and access properties from a string.

I’m gonna use a Generic function to make typing safe:

List<T> filterElementsInList<T extends JsonSerializable>({
  required String query,
  required String elementAttribute,
  required List<T> list,
}) {
  if (query.isEmpty) return list;
  return list.where((entity) => entity.toJSON()[elementAttribute].contains(query)).toList();
}

The use is as you already expect:

final users = [
  User(name: 'Darcey', email: '[email protected]'),
  User(name: 'Gisella', email: '[email protected]'),
  User(name: 'Eliot', email: '[email protected]'),
  User(name: 'Montgomery', email: '[email protected]'),
  User(name: 'Drucill', email: '[email protected]'),
];

final filtered = filterElementsInList(query: 'Eliot', elementAttribute: 'name', list: users);
print(filtered[0].email);

But the implementation in Dart?

reflect allows you to dynamically access the properties of an object without having to manually implement auxiliary methods. But this approach requires understanding the abstractions that language applies in its code, and it’s easy to fall into edge case. Read more on mirrors.

Example

List<T> filterElementsInList<T extends Object>({
  required String query,
  required String elementAttribute,
  required List<T> list,
}) {
  if (query.isEmpty) return list;
  return list.where((entity) => reflect(entity).getField(Symbol(elementAttribute)).reflectee.contains(query)).toList();
}
  • Thanks skin detailing the answer! As my classes already implement to/fromMap it will be easier to adopt this solution.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.