i have list view tasks and inside button to navigate question for this tasks and i can’t show this question problem with "Problem with dio type ‘String’ is not a subtype of type ‘Map<String, dynamic>’ in type cast"
My Repo
import 'dart:convert';
import 'package:dio/dio.dart';
import 'package:questonnaire_app/data/models/survey_data_model.dart';
import 'package:questonnaire_app/data/models/tasks_data_model.dart';
import 'package:questonnaire_app/network/dio_settings.dart';
class GetTasksRepo {
final Dio dio = DioSettings().dio;
Future<TasksDataModel> getTasks() async {
try {
final Response responce = await dio
.get('https://getquestionnairesendpoint-nfhw57yfsq-uc.a.run.app/');
if (responce.statusCode == 200) {
final Map<String, dynamic> jsonResponse = jsonDecode(responce.data);
return TasksDataModel.fromJson(jsonResponse);
} else {
throw Exception('Failed to load tasks');
}
} catch (e) {
print('Error $e');
rethrow;
}
}
Future<SurveyDataModel> getTasksById(String id) async {
try {
final Response response = await dio.get(
'https://getquestionnairesendpoint-nfhw57yfsq-uc.a.run.app/?id=$id');
if (response.statusCode == 200) {
print(response.data);
final jsonResponse = response.data as Map<String, dynamic>;
return SurveyDataModel.fromJson(jsonResponse);
} else {
throw Exception('Failed to load task by ID');
}
} catch (e) {
print('Error $e');
rethrow;
}
}
}
Survey Model
class SurveyDataModel {
String? message;
SurveyData? data;
SurveyDataModel({this.message, this.data});
SurveyDataModel.fromJson(Map<String, dynamic> json) {
message = json['message'];
data = json['data'] != null ? SurveyData.fromJson(json['data']) : null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['message'] = message;
if (this.data != null) {
data['data'] = this.data!.toJson();
}
return data;
}
}
class SurveyData {
String? id;
List<Pages>? pages;
SurveyData({this.id, this.pages});
SurveyData.fromJson(Map<String, dynamic> json) {
id = json['id'];
if (json['pages'] != null) {
pages = <Pages>[];
json['pages'].forEach((v) {
pages!.add(Pages.fromJson(v as Map<String, dynamic>));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
if (pages != null) {
data['pages'] = pages!.map((v) => v.toJson()).toList();
}
return data;
}
}
class Pages {
String? question;
String? type;
String? image;
List<String>? options;
Pages({this.question, this.type, this.image, this.options});
Pages.fromJson(Map<String, dynamic> json) {
question = json['question'];
type = json['type'];
image = json['image'];
options = json['options'].cast<String>();
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['question'] = question;
data['type'] = type;
data['image'] = image;
data['options'] = options;
return data;
}
}
My survey screen
import 'package:flutter/material.dart';
import 'package:questonnaire_app/data/models/survey_data_model.dart';
import 'package:questonnaire_app/data/repositories/get_tasks_repo.dart';
class SurveyScreen extends StatefulWidget {
final String surveyId;
const SurveyScreen({super.key, required this.surveyId});
@override
State<SurveyScreen> createState() => _SurveyScreenState();
}
class _SurveyScreenState extends State<SurveyScreen> {
late Future<SurveyDataModel> surveyDataModel;
int currentPageIndex = 0;
@override
void initState() {
super.initState();
surveyDataModel = GetTasksRepo().getTasksById(widget.surveyId);
}
void nextPage(int totalPages) {
setState(() {
if (currentPageIndex < totalPages - 1) {
currentPageIndex++;
}
});
}
void previousPage() {
setState(() {
if (currentPageIndex > 0) {
currentPageIndex--;
}
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
'Опросник',
style: TextStyle(
fontFamily: 'Nunito',
fontWeight: FontWeight.w800,
fontSize: 24,
color: Color(0xff27272E),
),
),
bottom: PreferredSize(
preferredSize: const Size.fromHeight(1),
child: Container(
color: const Color(0xff8E8E93).withOpacity(0.08),
height: 1.0,
),
),
),
body: FutureBuilder<SurveyDataModel>(
future: GetTasksRepo().getTasksById(widget.surveyId),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
} else if (snapshot.hasError) {
return Center(child: Text('Error: ${snapshot.error}'));
} else if (!snapshot.hasData || snapshot.data == null) {
return Center(child: Text('Survey not found'));
} else {
final surveyData = snapshot.data;
final currentPage = surveyData?.data?.pages?[currentPageIndex];
return currentPage == null
? Center(child: Text('No pages available'))
: Padding(
padding: EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
currentPage.question ?? "",
style: TextStyle(
fontFamily: "Nunito",
fontWeight: FontWeight.w800,
fontSize: 24,
color: Color(0xff27272E),
),
),
SizedBox(
height: 16,
),
if (currentPage.type == "multiple-choice")
ListView.builder(
shrinkWrap: true,
itemCount: currentPage.options?.length ?? 0,
itemBuilder: (context, index) {
final option = currentPage.options![index];
return ListTile(
title: Text(option),
onTap: () {},
);
},
),
if (currentPage.type == "checkbox")
ListView.builder(
shrinkWrap: true,
itemCount: currentPage.options?.length ?? 0,
itemBuilder: (context, index) {
final option = currentPage.options![index];
return CheckboxListTile(
title: Text(option),
value: false,
onChanged: (bool? value) {},
);
},
),
if (currentPage.type == 'banner')
Center(
child: Image.network(currentPage.image ?? ""),
),
Spacer(),
ElevatedButton(
onPressed: () {},
child: Text('Next'),
),
],
),
);
}
},
),
);
}
}
i want to show survey by id (all my tasks have id) after clicking my tasks i want see my surveys
2
Answers
While using
dio package
for network data streaming, no need to decode the returned data (body) because it’s purely in ajson
format. on the other handhttp
requires to decode the returned data.So, for your problem just construct your model object from the returned data (json) directly.
Understanding the Error and Context:
The error "Problem with dio type ‘String’ is not a subtype of type ‘Map<String, dynamic>’ in type cast" arises because Dio’s response data was assumed to be a JSON string, while you intended it to be a Dart Map<String, dynamic> object. This mismatch occurred in the getTasksById method of GetTasksRepo.dart.
Resolving the Issue and Navigation:
Automatic JSON Parsing with ResponseType.json:
Configure Dio to automatically parse the response as JSON:
This eliminates the need for manual decoding with jsonDecode.
Task List View Navigation:
Extract the task ID when a user clicks a task in the list view.
Pass the task ID to the SurveyScreen using navigation:
Survey Screen Update:
The SurveyScreen already receives the surveyId through its constructor. Use it directly in GetTasksRepo.getTasksById: