Home > Enterprise >  Dart map - type 'String' is not a subtype of type 'int' of 'index'
Dart map - type 'String' is not a subtype of type 'int' of 'index'

Time:03-18

I'm learning flutter by making an app following some youtube tutorials.

I have problem with showing search results in the app view. I'm able to query and get data from node backend but there's this error while mapping the json to model.

The data I'm getting from api is like this:

{id: <uuid>, 
userEmail: <email_string>, 
profile: [{profileName: <profile_name_string>, 
    profileImage: <image_url_string>, 
    profileBio: <profile_bio_string>}]
}

The error shows up in the profileName mapping line in the model.dart file.

class AccountModel {
  String userId;
  String userEmail;
  String? userPassword;

  AccountModel({
    required this.userId,
    required this.userEmail,
    this.userPassword,
  });
}

class ProfileModel {
  AccountModel accountModel;
  String? profileName;
  String profileImage;
  String? profileBio;

  ProfileModel({
    required this.accountModel,
    this.profileName,
    required this.profileImage,
    this.profileBio,
  });

  factory ProfileModel.fromMap({required Map<String, dynamic> map}) {
    print(map);
    return ProfileModel(
      profileName: map['profile']['profileName'],
      profileImage: map['profile']['profileImage'] ?? "default",
      profileBio: map['profile']['profileBio'],
      accountModel: AccountModel(
        userId: map['id'],
        userEmail: map['userEmail'],
        userPassword: map['userPassword'],
      ),
    );
  }

  factory ProfileModel.fromMapFollowerData(
      {required Map<String, dynamic> map}) {
    return ProfileModel(
      profileName: map['profileName'],
      profileImage: map['profileImage'] ?? "default",
      profileBio: map['profileBio'],
      accountModel: AccountModel(
        userId: map['userId'],
        userEmail: map['userEmail'],
      ),
    );
  }
}

Maybe I don't understand this correctly but I think that because the profile data is in [] I need to specify index.

How to rectify this error?

EDIT: New model after updating as guided by Majid:

class AccountModel {
  String userId;
  String userEmail;
  String? userPassword;
  final List<ProfileModel>? profile;

  AccountModel({
    required this.userId,
    required this.userEmail,
    this.userPassword,
    this.profile,
  });
  factory AccountModel.fromJson({required Map<String, dynamic> map}) {
    return AccountModel(
      userId: map['id'],
      userEmail: map['userEmail'],
      userPassword: map['userPassword'],
      profile: map['profile']
          .map((profileJson) => ProfileModel.fromJson(profileJson))
          .toList(),
    );
  }
}

class ProfileModel {
  String profileName;
  String profileImage;
  String? profileBio;

  ProfileModel({
    required this.profileName,
    required this.profileImage,
    this.profileBio,
  });

  factory ProfileModel.fromJson(profileJson, {Map<String, dynamic>? map}) {
    if (map != null) {
      return ProfileModel(
        profileName: map['profileName'],
        profileImage: map['profileImage'] ?? "default",
        profileBio: map['profileBio'],
      );
    } else {
      return ProfileModel(
        profileName: profileJson['profileName'],
        profileImage: profileJson['profileImage'] ?? "default",
        profileBio: profileJson['profileBio'],
      );
    }
  }
}

I was getting some errors because of how some functions in other pages that use the model are set up, so I made a few changes. I don't have errors in account/profile creation, post creation pages but still with the search page I have error. The error with the list now is:type 'List<dynamic>' is not a subtype of type 'List<ProfileModel>?'.

The error is where account model is mapping profile model and adding it to list. I tried making the list typed like:.toList<ProfileModel>(),, which I'm sure was stupid coz it shows NoSuchMethodError (NoSuchMethodError: Class 'MappedListIterable<dynamic, dynamic>' has no instance method 'toList' with matching arguments. Receiver: Instance of 'MappedListIterable<dynamic, dynamic>' Tried calling: toList<ProfileModel>() Found: toList({bool growable}) => List<X0>)

CodePudding user response:

The problem here is that profile is a List or Array of Map<String, String> here is your example

...
profile: [

{profileName: <profile_name_string>, 
    profileImage: <image_url_string>, 
    profileBio: <profile_bio_string>}
]

which means when you want to access this you have to iterate over the List to convert them all.

Which means this line in your model would become

 profileName: map['profile'][0]['profileName'],
 profileImage: map['profile'][0]['profileImage'] ?? "default",
 profileBio: map['profile'][0]['profileBio'],

However, this has a potential problem. Because you might have a List with no members which mean map['profile'][0] might be empty or null and another problem is that how about a time that profile has more than one member like you have map['profile][0] and map['profile'][1] and so on? in this case you are missing some of the members.

You can stick to only 0 index if you are sure that you always have a member and only one in your profile List but if you want to do this better you should probably do this like:

class UserAccountModel {
  UserAccountModel({
    this.id,
    this.userEmail,
    this.profile,
  });

  final String? id;
  final String? userEmail;
  final List<ProfileModel>? profile;

    factory UserAccountModel.fromJson(Map<String, dynamic> map) {
    final profile = map['profile'] as List<dynamic> ;
    return UserAccountModel(
      id: map['id'],
      userEmail: map['userEmail'],
      profile: profile.map((profileJson) => ProfileModel.fromJson(profileJson)).toList(),
    );
  }
}

class ProfileModel {
  ProfileModel({
    this.profileName,
    this.profileImage,
    this.profileBio,
  });

  final String? profileName;
  final String? profileImage;
  final String? profileBio;

  factory ProfileModel.fromJson(Map<String, String> map) {
    return ProfileModel(
      profileName: map['profileName'],
      profileImage: map['profileImage'] ?? "default",
      profileBio: map['profileBio'],
    );
  }
}

I strongly suggest you use json_serializable to avoid any mistakes.

  • Related