I am following this example.
https://esflutter.dev/docs/catalog/samples/expansion-tile-sample
to make an expandable of multi levels in the categories. I have a tree of up to 3 categories.
but it gives me this error: I put it in the image so it can be seen in which part is marking the error:
As I am relatively new, I have been trying to solve it for days but I do not realize that it could be, I also leave my model below because I think that there is the error, maybe there is some way other than .map? or I do not realize the solution, please if someone could help me.
// To parse this JSON data, do
//
// final categorias = categoriasFromJson(jsonString);
import 'dart:convert';
Categorias categoriasFromJson(String str) => Categorias.fromJson(json.decode(str));
String categoriasToJson(Categorias data) => json.encode(data.toJson());
class Categorias {
Categorias({
this.res,
this.id,
this.empresa,
this.idioma,
this.categorias,
});
int res;
int id;
int empresa;
String idioma;
List<Categoria> categorias;
factory Categorias.fromJson(Map<String, dynamic> json) => Categorias(
res: json["res"],
id: json["id"],
empresa: json["empresa"],
idioma: json["idioma"],
categorias: List<Categoria>.from(json["categorias"].map((x) => Categoria.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"res": res,
"id": id,
"empresa": empresa,
"idioma": idioma,
"categorias": List<dynamic>.from(categorias.map((x) => x.toJson())),
};
}
class Child {
Child({
this.id,
this.name,
this.img,
this.titulo,
this.children,
this.baos,
});
int id;
String name;
String img;
int titulo;
List<Categoria> children;
String baos;
factory Child.fromJson(Map<String, dynamic> json) => Child(
id: json["id"],
name: json["name"] == null ? null : json["name"],
img: json["img"],
titulo: json["titulo"],
children: json["children"] == null ? null : List<Categoria>.from(json["children"].map((x) => Categoria.fromJson(x))),
baos: json["Baños"] == null ? null : json["Baños"],
);
Map<String, dynamic> toJson() => {
"id": id,
"name": name == null ? null : name,
"img": imgValues.reverse[img],
"titulo": titulo,
"children": children == null ? null : List<dynamic>.from(children.map((x) => x.toJson())),
"Baños": baos == null ? null : baos,
};
}
class Categoria {
Categoria({
this.id,
this.name,
this.img,
this.titulo,
this.children,
});
int id;
String name;
String img;
int titulo;
List<Child> children;
factory Categoria.fromJson(Map<String, dynamic> json) => Categoria(
id: json["id"],
name: json["name"],
img: json["img"],
titulo: json["titulo"],
children: json["children"] == null ? null : List<Child>.from(json["children"].map((x) => Child.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"id": id,
"name": name,
"img": imgValues.reverse[img],
"titulo": titulo,
"children": children == null ? null : List<dynamic>.from(children.map((x) => x.toJson())),
};
}
enum Img { FOTOSCIRCULOS_INSECTICIDA_PNG, EMPTY }
final imgValues = EnumValues({
"": Img.EMPTY,
"fotoscirculos/insecticida.png": Img.FOTOSCIRCULOS_INSECTICIDA_PNG
});
class EnumValues<T> {
Map<String, T> map;
Map<T, String> reverseMap;
EnumValues(this.map);
Map<T, String> get reverse {
if (reverseMap == null) {
reverseMap = map.map((k, v) => new MapEntry(v, k));
}
return reverseMap;
}
}
EntryItem class:
class BuyView extends StatefulWidget {
final List<Categoria> categorias;
const BuyView({Key key, this.categorias}) : super(key: key);
@override
_BuyViewState createState() => _BuyViewState();
}
class _BuyViewState extends State<BuyView> {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('ExpansionTile'),
),
body: ListView.builder(
itemBuilder: (BuildContext context, int index) =>
EntryItem(widget.categorias[index]),
itemCount: widget.categorias.length,
),
),
);
}
}
// Displays one Entry. If the entry has children then it's displayed
// with an ExpansionTile.
class EntryItem extends StatelessWidget {
const EntryItem(this.entry);
final Categoria entry;
Widget _buildTiles(Categoria root) {
if (root.children.isEmpty) return ListTile(title: Text(root.name));
return ExpansionTile(
key: PageStorageKey<Categoria>(root),
title: Text(root.name),
children: root.children.map(_buildTiles).toList(),
);
}
@override
Widget build(BuildContext context) {
return _buildTiles(entry);
}
}
It seems that your Categoria
and Child
model share almost all of their attributes. The issue is that the _buildTiles
expects a Categoria
and the children of Categoria
are Child
.
If you merge the Child
and Categoria
models you can do as follows.
class EntryItem extends StatelessWidget {
const EntryItem(this.entry);
final Categoria entry;
Widget _buildTiles(Categoria root) {
if (root.children.isEmpty) return ListTile(title: Text(root.name));
return ExpansionTile(
key: PageStorageKey<Categoria>(root),
title: Text(root.name),
children: root.children.map((e)=>_buildTiles(e)).toList(),
);
}
@override
Widget build(BuildContext context) {
return _buildTiles(entry);
}
}
void main() {
runApp(ExpansionTileSample());
}
class Categoria {
Categoria({
this.id,
this.name,
this.img,
this.titulo,
this.children,
this.baos,
});
int id;
String name;
String img;
int titulo;
List<Categoria> children;
String baos;
factory Categoria.fromJson(Map<String, dynamic> json) => Categoria(
id: json["id"],
name: json["name"] == null ? null : json["name"],
img: json["img"],
titulo: json["titulo"],
children: json["children"] == null ? null : List<Categoria>.from(json["children"].map((x) => Categoria.fromJson(x))),
baos: json["Baños"] == null ? null : json["Baños"],
);
Map<String, dynamic> toJson() => {
"id": id,
"name": name == null ? null : name,
"img": imgValues.reverse[img],
"titulo": titulo,
"children": children == null ? null : List<dynamic>.from(children.map((x) => x.toJson())),
"Baños": baos == null ? null : baos,
};
}
enum Img { FOTOSCIRCULOS_INSECTICIDA_PNG, EMPTY }
final imgValues = EnumValues({
"": Img.EMPTY,
"fotoscirculos/insecticida.png": Img.FOTOSCIRCULOS_INSECTICIDA_PNG
});
class EnumValues<T> {
Map<String, T> map;
Map<T, String> reverseMap;
EnumValues(this.map);
Map<T, String> get reverse {
if (reverseMap == null) {
reverseMap = map.map((k, v) => new MapEntry(v, k));
}
return reverseMap;
}
}