Reputation: 675
I'm working on a very difficult task, (I'm new to flutter). I have JSON which I will get through api. JSON structure (one question - many answers) .Here he is:
"regionId": "f5e16375-5b03",
"objectid": "75226ff5-7124",
"actionid": "541ed524-7122",
"additions":
{
"name": "type of installation",
"id": "afa6cc6f-e2f8-11ec",
"variant": [
{
"name": "In the wall",
"id": "afa6cc6f-e2f8",
"additions":
{
"name": "Wall type",
"id": "afa6cc6f-e2f8",
"variant": [
{
"name": "Brick",
"id": "afa6cc6f-e2f8",
"additions": {
"name": null,
"id": null,
"variants": null
}
},
{
"name": "foam block",
"id": "afa6cc6f-e2f9",
"additions": {
"name": null,
"id": null,
"variants": null
}
},
]
}
}
]
}
}
I have questions and answers in JSON. And the next question depends on the previous answer. This is a hierarchy of questions and answers. My goal is to make these questions appear on the page gradually (one question after another). That is my API in the block works. I get the answer, I parse it. And the first question in the answer should appear on the page (drop-down list). Accordingly, after answering the first question there should be a second question with options, and so on indefinitely (conditionally). Until I choose the answer in which there will be no additional questions. And I can't figure out how to implement it. There may be as many as 2, 10 or 15 (any number) additional fees. Maybe someone has implemented something similar or there are examples. I can't figure out how to put everything on the shelves (question 1 - answer 1, question 2, answer 2). And I will be grateful for any help. Thank you) 2 main issues:
Upvotes: 2
Views: 224
Reputation: 910
I have checked your question and based on that I have prepared the answer.
To get the data similar to the demo you have shared, I prepared one model
class DropDownModel{
DropDownModel({this.name, this.id, this.variant, this.additions});
String? name;
String? id;
List<DropDownModel>? variant;
DropDownModel? additions;
}
To make the list as you are getting,
DropDownModel getModel() {
DropDownModel wallTypeBrick = DropDownModel(
name: "Brick", id: "afa6cc6f-e2f81", additions: DropDownModel());
DropDownModel wallTypeFoamBlock = DropDownModel(
name: "foam block", id: "afa6cc6f-e2f82", additions: DropDownModel());
DropDownModel outwallTypeBrick = DropDownModel(
name: "Out side Brick",
id: "afa6cc6f-e2f91",
additions: DropDownModel());
DropDownModel outwallTypeFoamBlock = DropDownModel(
name: "Out side foam block",
id: "afa6cc6f-e2f92",
additions: DropDownModel());
DropDownModel parent = DropDownModel();
parent.name = "type of installation";
parent.id = "afa6cc6f-e2f8-11ec";
DropDownModel wallTypeVariant = DropDownModel();
wallTypeVariant.name = "Wall type";
wallTypeVariant.id = "afa6cc6f-e2f8";
wallTypeVariant.variant = [wallTypeBrick, wallTypeFoamBlock];
DropDownModel inthewallvarient = DropDownModel();
inthewallvarient.name = "In the wall";
inthewallvarient.id = "afa6cc6f-e2f8";
inthewallvarient.additions = wallTypeVariant;
DropDownModel outwallTypeVariant = DropDownModel();
outwallTypeVariant.name = "Out Wall type";
outwallTypeVariant.id = "afa6cc6f-e2f9";
outwallTypeVariant.variant = [outwallTypeBrick, outwallTypeFoamBlock];
DropDownModel outinthewallvarient = DropDownModel();
outinthewallvarient.name = "Out side the wall";
outinthewallvarient.id = "afa6cc6f-e2f9";
outinthewallvarient.additions = outwallTypeVariant;
parent.variant = [inthewallvarient, outinthewallvarient];
return parent;
}
Prepared one model class to manage items
class Item{
Item({this.name, this.id, this.isSelected = false});
String? name;
String? id;
bool isSelected;
}
Below is the build method code.
@override
Widget build(BuildContext context) {
final Size size = MediaQuery.of(context).size;
return Scaffold(
//backgroundColor:AppGreen,
appBar: AppBar(
systemOverlayStyle: SystemUiOverlayStyle.dark.copyWith(
statusBarColor: Colors.red,
),
backgroundColor: Colors.red,
elevation: .10,
),
body: Container(
color: Colors.white,
child: Column(
children:
selectedQuestions.map((e) => getDropDownWidget(e)).toList(),
)),
);
}
Widget getDropDownWidget(Map<Item, List<Item?>> question) {
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(question.keys.toList()[0].name ?? ""),
DropdownButton<Item>(
value: selectedItems[question.keys.toList()[0]],
icon: const Icon(Icons.arrow_drop_down),
elevation: 16,
style: const TextStyle(color: Colors.black),
underline: Container(
height: 2,
color: Colors.red,
),
onChanged: (Item? newValue) {
setState(() {
var oldValue = selectedItems[question.keys.toList()[0]];
oldValue?.isSelected = false;
newValue?.isSelected = true;
selectedItems[question.keys.toList()[0]] = newValue!;
allQuestions.forEach((question) {
if (question.keys.toList()[0].id == newValue.id) {
selectedQuestions.add(question);
}
});
allQuestions.forEach((question) {
if (question.keys.toList()[0].id == oldValue?.id) {
selectedQuestions.remove(question);
}
});
});
},
items: ((question.values.toList()[0] ?? []) as List<Item>)
.map((Item value) {
return DropdownMenuItem<Item>(
value: value,
child: Text(value.name ?? ""),
);
}).toList(),
),
],
);
}
From the question model, I have prepared the list of questions by checking variant or additions
void getListOfQuestions(DropDownModel model) {
print("Check for ${model.name} and id >> ${model.id}");
if (model.variant != null || model.additions != null) {
if (model.variant != null) {
var item = getQuestion(model);
if (item != null) {
allQuestions.add(item);
}
} else if (model.additions != null) {
getListOfQuestions(model.additions!);
}
}
}
Map<Item, List<Item>>? getQuestion(DropDownModel model) {
print("getQuestion for ${model.name} and id >> ${model.id}");
if (model.variant != null) {
var options = <Item>[];
model.variant!.forEach((element) {
getListOfQuestions(element);
options.add(Item(id: element.id, name: element.name));
});
if (model.id != null) {
return {Item(id: model.id, name: model.name): options};
} else {
return null;
}
} else {
return null;
}
}
Complete code
class Home extends StatefulWidget {
Home({Key? key}) : super(key: key);
@override
State<Home> createState() => _HomeState();
}
class _HomeState extends State<Home> {
List<Map<Item, List<Item>>> allQuestions = [];
List<Map<Item, List<Item>>> selectedQuestions = [];
Map<Item, Item> selectedItems = HashMap();
@override
void initState() {
super.initState();
getListOfQuestions(getModel());
selectedQuestions.add(allQuestions[allQuestions.length - 1]);
}
@override
Widget build(BuildContext context) {
final Size size = MediaQuery.of(context).size;
return Scaffold(
//backgroundColor:AppGreen,
appBar: AppBar(
systemOverlayStyle: SystemUiOverlayStyle.dark.copyWith(
statusBarColor: Colors.red,
),
backgroundColor: Colors.red,
elevation: .10,
),
body: Container(
color: Colors.white,
child: Column(
children:
selectedQuestions.map((e) => getDropDownWidget(e)).toList(),
)),
);
}
Widget getDropDownWidget(Map<Item, List<Item?>> question) {
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(question.keys.toList()[0].name ?? ""),
DropdownButton<Item>(
value: selectedItems[question.keys.toList()[0]],
icon: const Icon(Icons.arrow_drop_down),
elevation: 16,
style: const TextStyle(color: Colors.black),
underline: Container(
height: 2,
color: Colors.red,
),
onChanged: (Item? newValue) {
setState(() {
var oldValue = selectedItems[question.keys.toList()[0]];
oldValue?.isSelected = false;
newValue?.isSelected = true;
selectedItems[question.keys.toList()[0]] = newValue!;
allQuestions.forEach((question) {
if (question.keys.toList()[0].id == newValue.id) {
selectedQuestions.add(question);
}
});
allQuestions.forEach((question) {
if (question.keys.toList()[0].id == oldValue?.id) {
selectedQuestions.remove(question);
}
});
});
},
items: ((question.values.toList()[0] ?? []) as List<Item>)
.map((Item value) {
return DropdownMenuItem<Item>(
value: value,
child: Text(value.name ?? ""),
);
}).toList(),
),
],
);
}
DropDownModel getModel() {
DropDownModel wallTypeBrick = DropDownModel(
name: "Brick", id: "afa6cc6f-e2f81", additions: DropDownModel());
DropDownModel wallTypeFoamBlock = DropDownModel(
name: "foam block", id: "afa6cc6f-e2f82", additions: DropDownModel());
DropDownModel outwallTypeBrick = DropDownModel(
name: "Out side Brick",
id: "afa6cc6f-e2f91",
additions: DropDownModel());
DropDownModel outwallTypeFoamBlock = DropDownModel(
name: "Out side foam block",
id: "afa6cc6f-e2f92",
additions: DropDownModel());
DropDownModel parent = DropDownModel();
parent.name = "type of installation";
parent.id = "afa6cc6f-e2f8-11ec";
DropDownModel wallTypeVariant = DropDownModel();
wallTypeVariant.name = "Wall type";
wallTypeVariant.id = "afa6cc6f-e2f8";
wallTypeVariant.variant = [wallTypeBrick, wallTypeFoamBlock];
DropDownModel inthewallvarient = DropDownModel();
inthewallvarient.name = "In the wall";
inthewallvarient.id = "afa6cc6f-e2f8";
inthewallvarient.additions = wallTypeVariant;
DropDownModel outwallTypeVariant = DropDownModel();
outwallTypeVariant.name = "Out Wall type";
outwallTypeVariant.id = "afa6cc6f-e2f9";
outwallTypeVariant.variant = [outwallTypeBrick, outwallTypeFoamBlock];
DropDownModel outinthewallvarient = DropDownModel();
outinthewallvarient.name = "Out side the wall";
outinthewallvarient.id = "afa6cc6f-e2f9";
outinthewallvarient.additions = outwallTypeVariant;
parent.variant = [inthewallvarient, outinthewallvarient];
return parent;
}
void getListOfQuestions(DropDownModel model) {
print("Check for ${model.name} and id >> ${model.id}");
if (model.variant != null || model.additions != null) {
if (model.variant != null) {
var item = getQuestion(model);
if (item != null) {
allQuestions.add(item);
}
} else if (model.additions != null) {
getListOfQuestions(model.additions!);
}
}
}
Map<Item, List<Item>>? getQuestion(DropDownModel model) {
print("getQuestion for ${model.name} and id >> ${model.id}");
if (model.variant != null) {
var options = <Item>[];
model.variant!.forEach((element) {
getListOfQuestions(element);
options.add(Item(id: element.id, name: element.name));
});
if (model.id != null) {
return {Item(id: model.id, name: model.name): options};
} else {
return null;
}
} else {
return null;
}
}
}
class Item {
Item({this.name, this.id, this.isSelected = false});
String? name;
String? id;
bool isSelected;
}
Please let me know if this works for you. If you are facing issue, please let me know.
Upvotes: 0
Reputation: 17812
You can try this
{
'q0a0':{
'que': 'first question here',
'options':['option1', 'option2', 'option3']
},
'q1a0':{
'que': 'second question here',
'options':['option1', 'option2', 'option3']
},
'q1a1':{
'que': 'second question here',
'options':['option1', 'option2', 'option3']
},
'q1a2':{
'que': 'second question here',
'options':['option1', 'option2', 'option3']
},
}
Here you can loop through each question. If user finished question 3 with answer 2 search for q3a2 and display it's question and answer
Upvotes: 1