I am running into state not initialize issue. The code works fine after the job has been created. If the job has not been created, then i get a error screen for like two seconds, then everything works fine.
I am pretty sure that it’s the widget loading before the _jobDocumentId is set but I can’t fix it!
video link: https://youtu.be/2xuuPAwW9g0
Error code:
════════ Exception caught by widgets library ═══════════════════════════════════
LateInitializationError: Field '_jobDocumentId@41263735' has not been initialized.
The relevant error-causing widget was
CreateUpdateJobView
lib/main.dart:26
════════════════════════════════════════════════════════════════════════════════
I/flutter ( 6024): TEXT CONTROLLER
I/flutter ( 6024): TEXT CONTROLLER OUTSIDE
class CreateUpdateJobView extends StatefulWidget {
const CreateUpdateJobView({Key? key}) : super(key: key);
@override
_CreateUpdateJobViewState createState() => _CreateUpdateJobViewState();
}
// https://youtu.be/VPvVD8t02U8?t=90350
class _CreateUpdateJobViewState extends State<CreateUpdateJobView> {
CloudJobApplication? _jobApplication;
CloudJob? _job;
late final FirebaseCloudStorage _jobsService;
late final TextEditingController _jobDescriptionController;
late final TextEditingController _jobAreaCodeController;
late final TextEditingController _jobStateController;
final currentUser = AuthService.firebase().currentUser!;
late final _jobDocumentId; // THIS IS THE ERROR VARIABLE
@override
void initState() {
//_jobDocumentId = null;
_jobsService = FirebaseCloudStorage();
_jobDescriptionController = TextEditingController();
_jobAreaCodeController = TextEditingController();
_jobStateController = TextEditingController();
super.initState();
}
void _jobDescriptionControllerListener() async {
// update database live when the job is being updated
final job = _job;
if (job == null) {
return;
}
await _jobsService.updateJob(
documentId: job.documentId,
jobDescription: _jobDescriptionController.text,
//jobState: _jobStateController.text,
);
}
void _setupTextControllerListener() {
final job = _job;
if (job != null) {
_jobStateController.text = job.jobState;
print('TEXT CONTROLLER');
}
print('TEXT CONTROLLER OUTSIDE');
_jobDescriptionController.removeListener(_jobDescriptionControllerListener);
_jobDescriptionController.addListener(_jobDescriptionControllerListener);
_jobAreaCodeController.removeListener(_jobDescriptionControllerListener);
_jobAreaCodeController.addListener(_jobDescriptionControllerListener);
_jobStateController.removeListener(_jobDescriptionControllerListener);
_jobStateController.addListener(_jobDescriptionControllerListener);
}
// I THINK THIS IS WHERE THE ISSUE IS!
Future<CloudJob> createOrGetExistingJob(BuildContext context) async {
final widgetJob = context.getArgument<CloudJob>();
if (widgetJob != null) {
_job = widgetJob;
_jobDescriptionController.text = widgetJob.jobDescription;
setState(() {
_jobDocumentId = widgetJob.documentId;
});
return widgetJob;
}
final existingJob = _job;
if (existingJob != null) {
setState(() {
_jobDocumentId = existingJob.documentId;
});
return existingJob;
}
// new job
final userId = currentUser.id;
final newJob = await _jobsService.createNewJob(jobCreatorId: userId);
setState(() {
_jobDocumentId = newJob.documentId;
});
_job = newJob;
return newJob;
}
void _deleteJobIfTextIsEmpty() {
final job = _job;
if (_jobDescriptionController.text.isEmpty && job != null) {
_jobsService.deleteJob(documentId: job.documentId);
}
}
void _saveJobIfTextNotEmpty() async {
final job = _job;
if (job != null && _jobDescriptionController.text.isNotEmpty) {
await _jobsService.updateJob(
documentId: job.documentId,
jobDescription: _jobDescriptionController.text,
//jobState: _jobStateController.text,
);
}
}
@override
void dispose() {
_deleteJobIfTextIsEmpty();
_saveJobIfTextNotEmpty();
_jobDescriptionController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('New Job'),
actions: [
IconButton(
onPressed: (() async {
print('create new job application');
final job = _job;
if (job == null) {
return;
}
final newJobApplication =
await _jobsService.createNewJobApplication(
jobCreatorId: currentUser.id,
jobId: job.documentId,
jobApplicationDescription: job.jobDescription);
//_jobApplication = newJobApplication;
}),
icon: const Icon(Icons.add),
)
],
),
body: Column(
children: [
FutureBuilder(
future: createOrGetExistingJob(context),
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.done:
_setupTextControllerListener();
// at this point we want to start to listening for changes
return Column(
//mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('Job State'),
Text(_jobStateController.text),
const SizedBox(height: 10),
const Text('Job description'),
TextField(
controller: _jobDescriptionController,
keyboardType: TextInputType.multiline,
maxLines: null,
decoration: const InputDecoration(
hintText: 'Describe job...',
),
),
const SizedBox(height: 10),
// const Text('Area code'),
// TextField(
// controller: _jobDescriptionController,
// keyboardType: TextInputType.multiline,
// maxLines: null,
// decoration: const InputDecoration(
// hintText: 'Describe job...',
// ),
// ),
]);
default:
return const CircularProgressIndicator();
}
},
),
_jobDocumentId == null ? Text('null') : Text(_jobDocumentId)
],
),
);
}
}