In a Flutter Web Application, I was trying to print the results of a Supabase query. The results are printed but only after a short flicker/red screen which is due to an error that is printed in the backend/command line. Also if I pressed the Back button, it will show the error.
══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
The following _TypeError was thrown building Builder:
TypeError: null: type 'Null' is not a subtype of type 'String'
The relevant error-causing widget was:
Builder
Builder:file:///C:/xxxxxx/Local/Pub/Cache/hosted/pub.dev/go_router-13.2.0/lib/src/builder.dart:249:9
When the exception was thrown, this was the stack:
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 297:3 throw_
dart-sdk/lib/_internal/js_shared/lib/rti.dart 1385:3 _failedAsCheck
dart-sdk/lib/_internal/js_shared/lib/rti.dart 1363:3 _generalAsCheckImplementation
packages/surveyweb/main.dart 31:45 <fn>
packages/go_router/src/builder.dart 250:21 <fn>
packages/flutter/src/widgets/basic.dart 7698:48 build
packages/flutter/src/widgets/framework.dart 5550:22 build
packages/flutter/src/widgets/framework.dart 5480:15 performRebuild
packages/flutter/src/widgets/framework.dart 5196:7 rebuild
packages/flutter/src/widgets/framework.dart 5556:5 update
packages/flutter/src/widgets/framework.dart 3824:14 updateChild
packages/flutter/src/widgets/framework.dart 6765:14 update
packages/flutter/src/widgets/framework.dart 3824:14 updateChild
packages/flutter/src/widgets/framework.dart 5505:16 performRebuild
...
I am a newbie in Flutter and most likely it is due to the handling of Futures and null safety. Kindly check my code and please suggest how to fix it or give a better approach. The page should get all the questions in the Supabase database then print it in the screen. This should never be null.
class Question {
final int id;
final String questionText;
final String? questionId;
final int mainCategoryId;
final int? subCategoryId;
Question(
{required this.id,
required this.questionText,
this.questionId,
required this.mainCategoryId,
this.subCategoryId});
Question.fromJson(Map<String, dynamic> json)
: id = json['id'],
questionText = json['question_text'],
questionId = json['question_id'],
mainCategoryId = json['main_category_id'],
subCategoryId = json['sub_category_id'];
}
class QuestionRepository {
final supabase = Supabase.instance.client;
Future<List<Question>> getQuestions() async {
try {
final response = await supabase.from('questions').select();
if (response.isNotEmpty) {
final questions =
response.map((data) => Question.fromJson(data)).toList();
return questions;
} else {
throw Exception('Failed to fetch questions!!');
}
} catch (error) {
throw Exception('Error fetching questions: $error');
}
}
}
class SurveyForm extends StatefulWidget {
const SurveyForm({super.key});
@override
State<SurveyForm> createState() => _SurveyFormState();
}
class _SurveyFormState extends State<SurveyForm> {
final QuestionRepository _questionRepository = QuestionRepository();
late Future<List<Question>> _questions;
Future<void> _fetchQuestions() async {
try {
final question = _questionRepository.getQuestions();
setState(() {
_questions = question;
});
} catch (error) {
const SnackBar(
content: Text('Unexpected Error'),
);
}
}
@override
void initState() {
super.initState();
_fetchQuestions();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Survey"),
),
body: FutureBuilder<List<Question>?>(
future: _questions,
builder: (context, snapshot) {
if (snapshot.hasData &&
snapshot.connectionState == ConnectionState.done) {
return ListView.builder(
itemCount: snapshot.data!.length,
itemBuilder: (context, index) {
return Text(snapshot.data?[index].questionText ?? " ");
},
);
} else {
return const CircularProgressIndicator();
}
},
));
}
}
2
Answers
I have found the error. It was not related to this page, but from a previous page. I was trying to pass an argument/parameter between pages using go_router. Sorry for the trouble.
You can use the
getQuestions()
directly, no need to call it in initState asFutureBuilder
will call it onbuild()
method: