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
- 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))),
);
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));
});
}