22

After hours of searching about the topic and due to lack of documentation on Flutter Web I am asking this question.

I was trying to create a web app using flutter and had an requirement where URL such as below

website.com/user/someUserCode

would be called and an page will be launched where the data (someUserCode) will be passed to the page

but haven't got any solutions yet to resolve it.

so just rounding it all up,

How to pass and fetch the data using (get / post) methods to flutter web app?

EDIT 1

What all I know / have tried yet

I am using below code to read if some parameters are being to some class file

final Map<String, String> params = Uri.parse(html.window.location.href).queryParameters;
String data = params["userData"];

all this actually solves the Fetch part of my question (maybe)

but the part where that data will be passed to the page via URL is still missing.

EDIT 2

Since I haven't got any replies and was not able to find anything i raised an ticket on Flutter GitHub page here

anyone else looking for the same issue can track it there (if it gets resolve)

Vicky Salunkhe
  • 9,869
  • 6
  • 42
  • 59

3 Answers3

8

May you could do it in a easy way:

import 'dart:html';
import 'package:flutter/material.dart';
import 'home_page.dart';

void getParams() {
  var uri = Uri.dataFromString(window.location.href);
  Map<String, String> params = uri.queryParameters;
  var origin = params['origin'];
  var destiny = params['destiny'];
  print(origin);
  print(destiny);
}

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Your app',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: HomePage(),
    );
  }
}

And then call it from browser:

http://localhost:52695/?origin=pointA&destiny=pointB

Output:

pointA
pointB 
Cassio Seffrin
  • 7,293
  • 1
  • 54
  • 54
4

I tried the above method from @Mariano Zorrilla but it still opened the pages in order:

/
/user
/user/yFbOfUAwx1OCC93INK8O7VqgBXq2

I have found Fluro, and works efficiently and cleanly you only need to add one routing file and do all the routing in one file rather than editing every page you want to route to, here's how you would implement it:

main.dart

void main() {
  FluroRouter.setupRouter();
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Website Title',
      onGenerateRoute: FluroRouter.router.generator
    );
  }
}

fluro_router.dart

class FluroRouter {
  static Router router = Router();
  //Define  your routers here
  static void setupRouter() {
    router.define('/', handler: _homeHandler);
    router.define('/login', handler: _loginHandler);
    router.define('/online-enquiry/:userId', handler: _userHandler);
  }
  //Add your handlers here
  static Handler _homeHandler = Handler(handlerFunc: (context, Map<String, dynamic> params) => Home());
  static Handler _loginHandler = Handler(handlerFunc: (context, Map<String, dynamic> params) => Login());
  static Handler _userHandler = Handler(handlerFunc: (context, Map<String, dynamic> params) => UserProfile(userID: params['userId'].first));
}

Source

Boy
  • 7,010
  • 4
  • 54
  • 68
Jackson Lee
  • 1,198
  • 4
  • 12
2

You can get everything (paths, parameters, etc) from onGenerateRoute. Your Home will be / and everything from there can be grabbed and used to redirect users.

My approach to solve this is the following. Your base App() should be like:

class App extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Website Title',
      onGenerateRoute: (settings) => NavigatorRoute.route(settings.name),
    );
  }
}

and the class NavigatorRoute will be:

class NavigatorRoute extends StatefulWidget {
  final String path;

  static Route<dynamic> route(String path) {
    return SimpleRoute(
      name: '', // this one is always empty as you didn't route yet
      title: 'Website Title',
      builder: (_) => NavigatorRoute(path: path),
      animated: false
    );
  }

  const NavigatorRoute({Key key, this.path}) : super(key: key);

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

class _NavigatorRouteState extends State<NavigatorRoute> {

  @override
  void initState() {
    super.initState();
    Future.microtask(() {
      if (widget.path == '/') {
        Navigator.of(context).pushAndRemoveUntil(HomeScreen.route(false), (_) => false);
        return;
      } else if (widget.path == '/user') {
        Navigator.of(context).pushAndRemoveUntil(UserScreen.route(false), (_) => false);
        return;
      } else if (widget.path.contains('/user/')) {
        Navigator.of(context).pushAndRemoveUntil(UserScreen.routeCode(widget.path.split('/')[2]), (_) => false);
        return;
      } else if (widget.path == '/about') {
        Navigator.of(context).pushAndRemoveUntil(AboutScreen.route(), (_) => false);
        return;
      } else {
        Navigator.of(context).pushAndRemoveUntil(HomeScreen.route(), (_) => false);
        return;
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return SizedBox();
  }
}

The code for the SimpleRoute is:

class SimpleRoute extends PageRoute {
  SimpleRoute({@required String name, @required this.title, @required this.builder, @required this.animated})
      : super(settings: RouteSettings(name: name));

  final String title;
  final WidgetBuilder builder;

  final bool animated;

  @override
  Color get barrierColor => null;

  @override
  String get barrierLabel => null;

  @override
  bool get maintainState => true;

  @override
  Duration get transitionDuration => Duration(milliseconds: 200);

  @override
  Widget buildPage(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) {
    return animated
        ? FadeTransition(
            opacity: animation,
            child: Title(
              title: this.title,
              color: Theme.of(context).primaryColor,
              child: builder(context),
            ),
          )
        : Title(
            title: this.title,
            color: Theme.of(context).primaryColor,
            child: builder(context),
          );
  }
}

So, finally... if you want to easily open one of your screens, you can do:

class HomeScreen extends StatefulWidget {
  static Route<dynamic> route(bool animated) {
      return SimpleRoute(name: '/', title: 'Home', builder: (_) => HomeScreen(), animated: animated);
  }

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

class _HomeScreenState extends State<HomeScreen> {
...
}

The routeCode could be:

static Route<dynamic> routeCode(String id) {
     return SimpleRoute(name: '/user/$id', title: 'User', builder: (_) => UserScreen(id: id), animated: false);
}

The main benefit of doing this is avoiding the stack of pages generated by accessing the last screen.

For example, if you're using directly the onGenerateRoute for "www.mywebsite.com/user/userId/edit" then Flutter will open:

  • Home Screen
  • User Screen
  • UserId Screen
  • Edit Screen

but with this approach, only "Edit Screen" will be open.

Mariano Zorrilla
  • 7,165
  • 2
  • 34
  • 52
  • How do you push a screen with your code? I can't figure it out. – carlosx2 Dec 02 '20 at 19:34
  • type the necessary URL and that's it. If your flutter web domain is "mywebsite.com" then, if you want to go to your privacy policies with "/policy" naming route, you do "mywebsite.com/#/privacy" and that's it. – Mariano Zorrilla Dec 03 '20 at 22:08