Home > Software design >  _TypeError (type 'List<dynamic>' is not a subtype of type 'List<Category>
_TypeError (type 'List<dynamic>' is not a subtype of type 'List<Category>

Time:04-27

I want to do a travel app so I am trying to create a smal demo data to specify my boilerplate code in my flutter app. But it gives me an type error. I have two model class which are Place and Category. But I can't relate this class. I am taking typError that I can't solve. _TypeError (type 'List' is not a subtype of type 'List')

Here is the debug panel:

════════ Exception caught by widgets library ═══════════════════════════════════
The following _TypeError was thrown building MainScreen(dirty):
type 'List<dynamic>' is not a subtype of type 'List<Category>'

The relevant error-causing widget was
MainScreen
When the exception was thrown, this was the stack
#0      places.<anonymous closure>
#1      MappedListIterable.elementAt (dart:_internal/iterable.dart:413:31)
#2      ListIterator.moveNext (dart:_internal/iterable.dart:342:26)
#3      new _GrowableList._ofEfficientLengthIterable (dart:core-patch/growable_array.dart:206:27)
#4      new _GrowableList.of (dart:core-patch/growable_array.dart:153:28)
#5      new List.of (dart:core-patch/array_patch.dart:51:28)
#6      ListIterable.toList (dart:_internal/iterable.dart:213:44)
#7      places
#8      places (package:seyahat_app/test.dart)
#9      MainScreen.build
#10     StatelessElement.build
#11     ComponentElement.performRebuild
#12     Element.rebuild
#13     ComponentElement._firstBuild
#14     ComponentElement.mount
...     Normal element mounting (171 frames)
#185    Element.inflateWidget
#186    MultiChildRenderObjectElement.inflateWidget
#187    MultiChildRenderObjectElement.mount
...     Normal element mounting (362 frames)
#549    Element.inflateWidget
#550    Element.updateChild
#551    RenderObjectToWidgetElement._rebuild
#552    RenderObjectToWidgetElement.mount
#553    RenderObjectToWidgetAdapter.attachToRenderTree.<anonymous closure>
#554    BuildOwner.buildScope
#555    RenderObjectToWidgetAdapter.attachToRenderTree
#556    WidgetsBinding.attachRootWidget
#557    WidgetsBinding.scheduleAttachRootWidget.<anonymous closure>
(elided 11 frames from class _RawReceivePortImpl, class _Timer, dart:async, and dart:async-patch)
════════════════════════════════════════════════════════════════════════════════

Here is my models and data list:

    class Place {
  final String name;
  final String image;
  final List<Category> category;

  Place({
    required this.name,
    required this.image,
    required this.category,
  });
}

class Category {
  final String name;

  Category({required this.name});
}

List<Place> places = placesData
    .map(
      (place) => Place(
        name: place["name"],
        image: place["image"],
        category: place["category"]
            .map(
              (category) => Category(
                name: category,
              ),
            )
            .toList(),
      ),
    )
    .toList();

List placesData = [
  {
    "name": "Dolmabahçe Sarayı",
    "image": "assets/images/dolmabahçe.jpg",
    "category": [
      "Museum",
    ],
  },
  {
    "name": "Ayasofya",
    "image": "assets/images/ayasofya.webp",
    "category": [
      "Museum",
    ]
  },
  {
    "name": "Yerebatan Sarnıcı",
    "image": "assets/images/yerebatan.webp",
    "category": [
      "Museum",
    ]
  }
];

var categoriesData = [
  {"name": "Müze"},
  {"name": "Restorant"},
  {"name": "Eğlence"},
  {"name": "Alışveriş"},
];

If you help me I will be very happy...

CodePudding user response:

Bad typecasting. Look at the example.

Example:

void main() {
  places.forEach(print);
}

class Place {
  final String name;
  final String image;
  final List<Category> category;

  Place({
    required this.name,
    required this.image,
    required this.category,
  });

  @override
  String toString() => 'Place(name: $name, image: $image, category: $category)';
}

class Category {
  final String name;

  Category({required this.name});
  
  @override
  String toString() => 'Category(name: $name)';
}

List<Place> places = [
  for (final place in placesData)
    Place(
      name: place["name"],
      image: place["image"],
      category: [
        // Here you need cast as Type
        // Or `List<String>.from(place["category"])`
        for (final category in place["category"] as List<String>)
          Category(name: category),
      ],
    ),
];

List placesData = [
  {
    "name": "Dolmabahçe Sarayı",
    "image": "assets/images/dolmabahçe.jpg",
    "category": [
      "Museum",
    ],
  },
  {
    "name": "Ayasofya",
    "image": "assets/images/ayasofya.webp",
    "category": [
      "Museum",
    ]
  },
  {
    "name": "Yerebatan Sarnıcı",
    "image": "assets/images/yerebatan.webp",
    "category": [
      "Museum",
    ]
  }
];

Output:

Place(name: Dolmabahçe Sarayı, image: assets/images/dolmabahçe.jpg, category: [Category(name: Museum)])
Place(name: Ayasofya, image: assets/images/ayasofya.webp, category: [Category(name: Museum)])
Place(name: Yerebatan Sarnıcı, image: assets/images/yerebatan.webp, category: [Category(name: Museum)])

CodePudding user response:

factory constructor

  1. Add fromMap named constructor to Place class
factory Place.fromMap(Map<String, dynamic> places) => Place(
      name: places["name"],
      image: places["image"],
      category: List<Category>.from(
          places["category"].map((name) => Category(name: name))),
    );
  1. Assign data to a places list like that:

    List<Place> places = placesData.map((item) => Place.fromMap(item)).toList();
    

Full code:

class Place {
  final String name;
  final String image;
  final List<Category> category;

  Place({
    required this.name,
    required this.image,
    required this.category,
  });

  // Add from map named constructor to the model
  factory Place.fromMap(Map<String, dynamic> places) => Place(
        name: places["name"],
        image: places["image"],
        category: List<Category>.from(
            places["category"].map((name) => Category(name: name))),
      );
}

class Category {
  final String name;

  Category({required this.name});
}

void main() {
  List placesData = [
    {
      "name": "Dolmabahçe Sarayı",
      "image": "assets/images/dolmabahçe.jpg",
      "category": [
        "Museum",
      ],
    },
    {
      "name": "Ayasofya",
      "image": "assets/images/ayasofya.webp",
      "category": [
        "Museum",
      ]
    },
    {
      "name": "Yerebatan Sarnıcı",
      "image": "assets/images/yerebatan.webp",
      "category": [
        "Museum",
      ]
    }
  ];

  var categoriesData = [
    {"name": "Müze"},
    {"name": "Restorant"},
    {"name": "Eğlence"},
    {"name": "Alışveriş"},
  ];

  //adding data to the list
  List<Place> places = placesData.map((item) => Place.fromMap(item)).toList();

  // print statement to check if the data is added successfully
  places.forEach((item) {
    print(item.name);
    print('');
    item.category.forEach((category) => print(category.name));
  });
}
  • Related