Home > Mobile >  Why doesn't Flutter Login Page show Scaffold Message error for wrong credentials using response
Why doesn't Flutter Login Page show Scaffold Message error for wrong credentials using response

Time:08-16

I am a beginner in Flutter. I am using an API to login users in an app. I have set in my login code that a Scaffold Message should show if the response code is not 200. However I am also saving the access token that is returned using Shared Preferences so that I can use it to manage state. The access token is returned only when the response code is 200. The problem is that when the wrong credentials are entered, instead of the scaffold message showing, the screen just shows the loading circle until I reload the app. It looks like this this is the login page after entering wrong credentials

The error that is given comes up on the object_patch.dart file this is the error that shows in the object patch file

The debug console display is as below:

   E/flutter (24326): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: NoSuchMethodError: The method '[]' was called on null.
E/flutter (24326): Receiver: null
E/flutter (24326): Tried calling: []("accessToken")
E/flutter (24326): #0      Object.noSuchMethod (dart:core-patch/object_patch.dart:38:5)
E/flutter (24326): #1      _LoginWidgetState._login
package:mne/User/login_widget.dart:50
E/flutter (24326): <asynchronous suspension>
E/flutter (24326): #2      _LoginWidgetState.build.<anonymous closure>
package:mne/User/login_widget.dart:180
E/flutter (24326): <asynchronous suspension>
E/flutter (24326):

The code I have used in my login page is as below:

import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:mne/Network/api.dart';

import 'package:shared_preferences/shared_preferences.dart';

class LoginWidget extends StatefulWidget {
  const LoginWidget({Key? key}) : super(key: key);

  @override
  _LoginWidgetState createState() => _LoginWidgetState();
}

class _LoginWidgetState extends State<LoginWidget> {
  final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();

  void _showScaffold(String message) {
    ScaffoldMessenger.of(context).showSnackBar(SnackBar(
        content: Text(message, style: const TextStyle(color: Colors.white)),
        action: SnackBarAction(
          textColor: Colors.white,
          label: 'Try Again',
          onPressed: () {
            Navigator.of(context).pushReplacementNamed('login');
          },
        ),
        backgroundColor: Colors.redAccent));
  }

  // @override
  // void initState() {
  //   super.initState();
  //   _showScaffold('Invalid Credentials');
  // }

  TextEditingController emailController = TextEditingController();
  final TextEditingController passwordController = TextEditingController();
  final _controller = TextEditingController();

  _login() async {
    var data = {
      'email': emailController.text,
      'password': passwordController.text,
    };

    var res = await Network().authData(data, 'auth/login');
    var body = json.decode(res.body);
    var tdata = body['data'];
    var access = tdata['accessToken'];
    var user = tdata['user'];

    if (res.statusCode != 200) {
      _showScaffold(body['Invalid Credentials']);
    }

    if (res.statusCode == 200) {
      SharedPreferences localStorage = await SharedPreferences.getInstance();
      localStorage.setString('token', json.encode(access));
      localStorage.setString('user', json.encode(user));
      return Navigator.of(context).pushReplacementNamed('dashboard');
    }
    // else {
    //   return setState(() {
    //     _showScaffold('Invalid Credentials');
    //   });
    // }
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  bool _isObscure = true;
  bool _validate = false;
  bool _isLoading = true;

  @override
  Widget build(BuildContext context) {
    // ignore: avoid_unnecessary_containers
    return Container(
        key: _scaffoldKey,
        child: Column(
          children: [
            Container(
              margin: const EdgeInsets.only(left: 10),
              alignment: Alignment.centerLeft,
              child: const Text('Email',
                  style: TextStyle(fontWeight: FontWeight.bold)),
            ),
            Container(
                padding: const EdgeInsets.fromLTRB(10, 10, 10, 0),
                child: SizedBox(
                    height: 60.0,
                    width: 375,
                    child: TextFormField(
                      controller: emailController,
                      autovalidateMode: AutovalidateMode.onUserInteraction,
                      validator: (value) {
                        if (value!.isEmpty) {
                          return 'Field cannot be empty';
                        }
                      },
                      keyboardType: TextInputType.emailAddress,
                      decoration: InputDecoration(
                        errorText: _validate ? 'Field cannot be empty' : null,
                        border: const OutlineInputBorder(),
                        labelText: 'Email Address',
                      ),
                    ))),
            Container(
              padding: const EdgeInsets.only(top: 10),
              margin: const EdgeInsets.only(left: 10),
              alignment: Alignment.centerLeft,
              child: const Text('Password',
                  style: TextStyle(fontWeight: FontWeight.bold)),
            ),
            Container(
                margin: const EdgeInsets.fromLTRB(10, 10, 10, 0),
                padding: const EdgeInsets.only(bottom: 15),
                child: SizedBox(
                    height: 60.0,
                    width: 375,
                    child: TextFormField(
                      controller: passwordController,
                      obscureText: _isObscure,
                      autovalidateMode: AutovalidateMode.onUserInteraction,
                      validator: (value) {
                        if (value!.isEmpty) {
                          return 'Field cannot be empty';
                        }
                      },
                      keyboardType: TextInputType.text,
                      decoration: InputDecoration(
                        suffixIcon: IconButton(
                            icon: Icon(_isObscure
                                ? Icons.visibility
                                : Icons.visibility_off),
                            onPressed: () {
                              FocusScope.of(context).unfocus();
                              setState(() {
                                _isObscure = !_isObscure;
                              });
                            }),
                        errorText: _validate ? 'Field cannot be empty' : null,
                        border: const OutlineInputBorder(),
                        labelText: 'Password',
                      ),
                    ))),
            Container(
                alignment: Alignment.centerLeft,
                padding: const EdgeInsets.only(left: 10, top: 15, bottom: 15),
                child: TextButton(
                  child: const Text(
                    'Forgot password?',
                    style: TextStyle(
                        color: Color.fromRGBO(0, 161, 93, 1),
                        fontWeight: FontWeight.bold,
                        fontSize: 16),
                  ),
                  onPressed: () {
                    Navigator.of(context).pushNamed('reset');
                  },
                )),
            if (_isLoading)
              SizedBox(
                  width: 250,
                  height: 50,
                  child: ElevatedButton(
                    style: ButtonStyle(
                        backgroundColor: MaterialStateProperty.all<Color>(
                      const Color.fromRGBO(0, 161, 39, 1),
                    )),
                    onPressed: () async {
                      setState(() {
                        _isLoading = false;
                      });
                      await _login();
                      if (!mounted) return;
                      setState(() {
                        _isLoading = true;
                      });
                    },
                    child: const Text(
                      'Log In',
                      style: TextStyle(
                        fontSize: 18,
                        fontWeight: FontWeight.bold,
                        color: Colors.white,
                      ),
                    ),
                  ))
            else
              const Center(
                  child: CircularProgressIndicator(
                      backgroundColor: Color.fromRGBO(0, 161, 39, 1))),
          ],
        ));
  }
}

I have tried using the super.init State for the show scaffold message function before the login function like this:

@override
       void initState() {
         super.initState();
        _showScaffold('Invalid Credentials');
       }

And I have tried to use an else statement inside the login function like this:

if (res.statusCode == 200) {
          SharedPreferences localStorage = await SharedPreferences.getInstance();
          localStorage.setString('token', json.encode(access));
          localStorage.setString('user', json.encode(user));
          return Navigator.of(context).pushReplacementNamed('dashboard');
        }
         else {
           return setState(() {
             _showScaffold('Invalid Credentials');
           });
         }

Please help me figure out why the error message isn't displaying and how I can show this properly. Thank you.

CodePudding user response:

I think the issue is that you're first doing the conversions when you get a response, and only then check if it was even successful so just move this code under res.statusCode == 200

var body = json.decode(res.body);
var tdata = body['data'];
var access = tdata['accessToken'];
var user = tdata['user'];
  • Related