skip to Main Content

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


  1. While using dio package for network data streaming, no need to decode the returned data (body) because it’s purely in a json format. on the other hand http requires to decode the returned data.

    So, for your problem just construct your model object from the returned data (json) directly.

      if (responce.statusCode == 200) {
        return TasksDataModel.fromJson(responce.data);
      } 
    
    Login or Signup to reply.
  2. 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:

    Future<SurveyDataModel> getTasksById(String id) async {
      try {
        final Response response = await dio.get(
            'https://getquestionnairesendpoint-nfhw57yfsq-uc.a.run.app/?id=$id',
            options: Options(responseType: ResponseType.json),
        );
        if (response.statusCode == 200) {
          final jsonResponse = response.data; // No manual decoding needed
          return SurveyDataModel.fromJson(jsonResponse);
        } else {
          throw Exception('Failed to load task by ID');
        }
      } catch (e) {
        print('Error $e');
        rethrow;
      }
    }
    

    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:

    // In your task list view widget (assuming it's a ListTile)
    onTap: () {
      final taskId = task.id; // Replace 'task' with your actual data
      Navigator.push(
        context,
        MaterialPageRoute(
          builder: (context) => SurveyScreen(surveyId: taskId),
        ),
      );
    },
    

    Survey Screen Update:

    The SurveyScreen already receives the surveyId through its constructor. Use it directly in GetTasksRepo.getTasksById:

    @override
    void initState() {
      super.initState();
      surveyDataModel = GetTasksRepo().getTasksById(widget.surveyId);
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search