Giter VIP home page Giter VIP logo

Comments (10)

daviddomkar avatar daviddomkar commented on July 20, 2024 1

@Mashood97

Thank you, that indeed works. I originaly did not want to go with context.go because I wanted to replace the page and not create a history entry. But I found out that there is Router.neglect for that so using context.go is sufficient for me. But I think I do not fully understand the purpose of context.replace and context.pushReplacement then. For me these methods are basically just breaking the navigation state.

from flutter.

darshankawar avatar darshankawar commented on July 20, 2024

@iSaqibShafique
Please provide complete runnable reproducible code sample without third party package implementation.
You may check similar issues reported for the package and see if they resemble your case or not:

#147229
#144298

from flutter.

daviddomkar avatar daviddomkar commented on July 20, 2024

Same issue for me

from flutter.

Mashood97 avatar Mashood97 commented on July 20, 2024

@daviddomkar @iSaqibShafique

I guess there's an issue here on your redirect method for splash where you're returning null,
instead you can use this below code for redirect and check if it helps:

redirect: (context, state) { User? user = FirebaseAuthService().currentuser.toValueNotifier().value; if (user != null && user.emailVerified) { return maindashboardview; } else if (user != null && user.emailVerified == false) { return emailnotverified; } else { return login; }

If it doesn't then I think you have the same name and path which is not the case in go router, a path contains "/" but the name shouldn't, you might need to tweak that as well for e.g.

GoRoute(
path: "/login",
name: "login",
builder: (context, state) => const LoginView(),
),

  Try to follow these two steps if it doesn't help then share the code you're using for navigation as well.

from flutter.

daviddomkar avatar daviddomkar commented on July 20, 2024

Hello @Mashood97 @darshankawar

Thanks for your inputs. I created a minimal reproduction where my problem occurs.

Here is the link to the reproduction repository: https://github.com/daviddomkar/go-router-location-empty-reproduction

More details and description of the problem:

I think the issue is with context.replace on a top level route. In my example there are 3 routes:

  • home route ('/')
  • login route ('/auth/login')
  • signup route ('/auth/signup')

I have setup my state using a ChangeNotifier with a boolean which tells if the user is authenticated or not. I use this ChangeNotifier as a refreshListenable on the GoRouter.

I have then setup the redirects in such a way that authenticated user is always redirected to home route and unauthenticated user is redirected to login route, from which he can go to signup route via a context.replace('/auth/signup'), he can also go back to login route using context.replace('/auth/login'), any other form of routing is handled by the refreshListenable using signUp(), logIn() and logOut() methods.

The issue is when I launch the app (state is unauthenticated) and I am on the login route. Then I press "Go to Sign Up" button. I am redirected via context.replace('/auth/signup') to the signup route and when I click on the "Sign Up" button which calls signUp() state method which triggers a redirect using refreshListenable the exception "GoException (GoException: Location cannot be empty.)" is thrown.

I would instead assume the correct behavior to be to redirect me to the home route.

from flutter.

Mashood97 avatar Mashood97 commented on July 20, 2024

@daviddomkar

Yeah that's because you are directly handling every case inside each GoRoute redirect method. I would recommend you to use redirect method directly inside the GoRouter constructor. As per my understanding this below condition might work for you:

First define pre auth routes in a list as routes.

 List<String> routes = [
   "/auth/signup",
   "/auth/login"
    ];
 
  redirect: (ctx, state) async {
  // check if you are authenticated with your auth state class.

  final status = _state.isAuthenticated;

  final loggedIn = status;

  // Check if your logging in i.e on pre auth routes.
  final logging = routes.contains(state.matchedLocation);

  if (!loggedIn && !logging) return "/auth/login";

  if (loggedIn && logging) return "/";

  return null;
},
//Set initial location
 initialLocation: _state.isAuthenticated
    ? "/";
    : "/auth/login",

I guess this might work for you in this case, Please try and let me know if it helps.

from flutter.

daviddomkar avatar daviddomkar commented on July 20, 2024

@Mashood97

Thanks for the reply. Unfortunately, I am still experiencing the exception even with your suggestion. I have updated my reproduction repository if you would like to try it.

from flutter.

godilite avatar godilite commented on July 20, 2024

@daviddomkar

I had same issue, I get my listenable from getIt, like this
refreshListenable : getIt<AuthViewModel>().authListenable ------ Error location cannot be empty
refreshListenable : getIt.get<AuthViewModel>().authListenable ------ NO ERRORS

so I guess it is something to do with how you get the object

from flutter.

Mashood97 avatar Mashood97 commented on July 20, 2024

@daviddomkar

I ran your code provided on repository, I made some couple of changes in code can you use this below code:

import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';

class AuthState extends ChangeNotifier {
  bool _isAuthenticated = false;

  bool get isAuthenticated => _isAuthenticated;

  void signUp() {
    _isAuthenticated = true;
    notifyListeners();
  }

  void logIn() {
    _isAuthenticated = true;
    notifyListeners();
  }

  void logOut() {
    _isAuthenticated = false;
    notifyListeners();
  }
}

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  late final AuthState _state;
  late final GoRouter _router;

  List<String> routes = ["/auth/signup", "/auth/login"];

  @override
  void initState() {
    super.initState();

    _state = AuthState();

    _router = GoRouter(
      refreshListenable: _state,
      initialLocation: _state.isAuthenticated ? "/" : "/auth/login",
      redirect: (context, state) {
        final status = _state.isAuthenticated;

        final loggedIn = status;

        final logging = routes.contains(state.matchedLocation);

        if (!loggedIn && !logging) return "/auth/login";

        if (loggedIn && logging) return "/";

        return null;
      },
      routes: [
        GoRoute(
          path: '/',
          builder: (context, state) => MyHomePage(
            state: _state,
          ),
        ),
        GoRoute(
          path: '/auth/signup',
          builder: (context, state) => MySignupPage(
            state: _state,
          ),
        ),
        GoRoute(
          path: '/auth/login',
          builder: (context, state) => MyLoginPage(
            state: _state,
          ),
        ),
      ],
    );
  }

  @override
  void dispose() {
    _router.dispose();
    _state.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      title: 'Go Router Location Empty Exception Reproduction',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      routerConfig: _router,
    );
  }
}

class MyHomePage extends StatelessWidget {
  final AuthState state;

  const MyHomePage({
    super.key,
    required this.state,
  });

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            state.logOut();
          },
          child: const Text('Log out'),
        ),
      ),
    );
  }
}

class MyLoginPage extends StatelessWidget {
  const MyLoginPage({
    super.key,
    required this.state,
  });

  final AuthState state;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            ElevatedButton(
              onPressed: () {
                state.logIn();
              },
              child: const Text('Log In'),
            ),
            ElevatedButton(
              onPressed: () {
                context.go('/auth/signup');
              },
              child: const Text('Go to Sign Up'),
            ),
          ],
        ),
      ),
    );
  }
}

class MySignupPage extends StatelessWidget {
  const MySignupPage({
    super.key,
    required this.state,
  });

  final AuthState state;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            ElevatedButton(
              onPressed: () {
                state.signUp();
              },
              child: const Text('Sign Up'),
            ),
            ElevatedButton(
              onPressed: () {
                context.go('/auth/login');
              },
              child: const Text('Go to Log In'),
            ),
          ],
        ),
      ),
    );
  }
}

from flutter.

Mashood97 avatar Mashood97 commented on July 20, 2024

@daviddomkar
Glad it works for you, Good luck

from flutter.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.