Repository: Stacked-Org/stacked

Issue:
[bug]: bottom nav bar example shows wrong selected nav bar item after browser refresh
### Describe the bug

The bottom nav bar example demonstrates the usage of the `NestedRouter()` with an `AppBar()` Widget. Selecting the NavBar Item 'History' e.g. will select the item and leads to this url: `.../bottom-nav-example/history-view`. After refreshing the browser, the url is still the same as expected and also shows the `HistoryView` but the favorites icon is selected. 

### To reproduce

1. Run router_example
2. Navigate to history view via the app bar item
3. Refresh the browser
4. HistoryView is shown but Favorites Icon is selected

### Expected behavior

Since there are many scenarios where Nested Routing is used with an appbar the expected behavior in web would be to see the correct nav bar item selected. 

### Screenshots

![Bildschirmfoto 2023-03-22 um 14 18 22](https://user-images.githubusercontent.com/43975565/226916580-827bcb0f-8c30-44c3-9801-34f1dfcb4f88.png)


### Additional Context

_No response_


Discussion: @mraaz97 yes, I actually saw this when I migrated the web app. It can be fixed using [exactly this technique](https://youtu.be/cGdNRnBdWpw?t=331) to get the url path id and match it with the tab. 

When we get some time we will update the example to include this information. Thank you for creating the issue. It will help make sure it doesn't slip through the cracks.
Fix the issue in the example using the described solution. 
@mraaz97 where is the example app you mentioned? I wanna work on this bug.
Hi @ferrarafer, you can find it here: https://github.com/Stacked-Org/stacked/blob/master/example/router_example/lib/ui/bottom_nav/bottom_nav_example.dart

Fix patch:
diff --git a/example/navigator_example/pubspec.yaml b/example/navigator_example/pubspec.yaml
index 2c91bdb36..8c89cd7a6 100644
--- a/example/navigator_example/pubspec.yaml
+++ b/example/navigator_example/pubspec.yaml
@@ -23,7 +23,7 @@ dependencies:
 
   # The following adds the Cupertino Icons font to your application.
   # Use with the CupertinoIcons class for iOS style icons.
-  cupertino_icons: ^0.1.2
+  cupertino_icons: ^1.0.2
 
   # state management
   stacked:
diff --git a/example/router_example/lib/app/app.dart b/example/router_example/lib/app/app.dart
index 84cdeadba..1250336aa 100644
--- a/example/router_example/lib/app/app.dart
+++ b/example/router_example/lib/app/app.dart
@@ -32,10 +32,6 @@ import 'custom_route_transition.dart';
     MaterialRoute(page: HomeView, initial: true),
     MaterialRoute(page: BottomNavExample, children: [
       RedirectRoute(path: '', redirectTo: 'favorites'),
-      CustomRoute(
-        page: HistoryView,
-        transitionsBuilder: TransitionsBuilders.fadeIn,
-      ),
       AdaptiveRoute(
         path: 'favourites',
         page: FavoritesView,
@@ -44,6 +40,10 @@ import 'custom_route_transition.dart';
           CustomRoute(page: HistoryView),
         ],
       ),
+      CustomRoute(
+        page: HistoryView,
+        transitionsBuilder: TransitionsBuilders.fadeIn,
+      ),
       CupertinoRoute(page: ProfileView),
     ]),
     MaterialRoute(page: StreamCounterView),
diff --git a/example/router_example/lib/app/app.router.dart b/example/router_example/lib/app/app.router.dart
index 300cd043b..05862f590 100644
--- a/example/router_example/lib/app/app.router.dart
+++ b/example/router_example/lib/app/app.router.dart
@@ -4,38 +4,31 @@
 // StackedRouterGenerator
 // **************************************************************************
 
-// GENERATED CODE - DO NOT MODIFY BY HAND
-
-// **************************************************************************
-// StackedRouterGenerator
-// **************************************************************************
-//
-// ignore_for_file: type=lint
-
 // ignore_for_file: no_leading_underscores_for_library_prefixes
 import 'package:flutter/material.dart' as _i13;
 import 'package:stacked/stacked.dart' as _i12;
-import 'package:stacked_services/stacked_services.dart' as _i1;
+import 'package:stacked_services/stacked_services.dart' as _i11;
 
 import '../datamodels/clashable_one.dart' as _i15;
 import '../datamodels/clashable_two.dart' as _i16;
-import '../datamodels/home_type.dart' as _i3;
-import '../ui/bottom_nav/bottom_nav_example.dart' as _i4;
-import '../ui/bottom_nav/favorites/favorites_view.dart' as _i9;
+import '../datamodels/home_type.dart' as _i1;
+import '../ui/bottom_nav/bottom_nav_example.dart' as _i3;
+import '../ui/bottom_nav/favorites/favorites_view.dart' as _i7;
 import '../ui/bottom_nav/history/history_view.dart' as _i8;
-import '../ui/bottom_nav/profile/profile_view.dart' as _i10;
-import '../ui/form/example_form_view.dart' as _i6;
+import '../ui/bottom_nav/profile/profile_view.dart' as _i9;
+import '../ui/form/example_form_view.dart' as _i5;
 import '../ui/home/home_view.dart' as _i2;
 import '../ui/multiple_futures_example/multiple_futures_example_view.dart'
-    as _i11;
-import '../ui/nonreactive/nonreactive_view.dart' as _i7;
-import '../ui/stream_view/stream_counter_view.dart' as _i5;
+    as _i10;
+import '../ui/nonreactive/nonreactive_view.dart' as _i6;
+import '../ui/stream_view/stream_counter_view.dart' as _i4;
 import 'custom_route_transition.dart' as _i14;
 
-final stackedRouter = StackedRouterWeb(_i1.StackedService.navigatorKey);
+final stackedRouter =
+    StackedRouterWeb(navigatorKey: _i11.StackedService.navigatorKey);
 
 class StackedRouterWeb extends _i12.RootStackRouter {
-  StackedRouterWeb([_i13.GlobalKey<_i13.NavigatorState>? navigatorKey])
+  StackedRouterWeb({_i13.GlobalKey<_i13.NavigatorState>? navigatorKey})
       : super(navigatorKey);
 
   @override
@@ -52,79 +45,73 @@ class StackedRouterWeb extends _i12.RootStackRouter {
           clashableGetter: args.clashableGetter,
           homeTypes: args.homeTypes,
         ),
-        maintainState: false,
       );
     },
     BottomNavExampleRoute.name: (routeData) {
       return _i12.MaterialPageX<dynamic>(
         routeData: routeData,
-        child: const _i4.BottomNavExample(),
-        maintainState: false,
+        child: const _i3.BottomNavExample(),
       );
     },
     StreamCounterViewRoute.name: (routeData) {
       final args = routeData.argsAs<StreamCounterViewArgs>();
       return _i12.MaterialPageX<dynamic>(
         routeData: routeData,
-        child: _i5.StreamCounterView(
+        child: _i4.StreamCounterView(
           key: args.key,
           clashableTwo: args.clashableTwo,
         ),
-        maintainState: false,
       );
     },
     ExampleFormViewRoute.name: (routeData) {
       final args = routeData.argsAs<ExampleFormViewArgs>();
       return _i12.MaterialPageX<dynamic>(
         routeData: routeData,
-        child: _i6.ExampleFormView(
+        child: _i5.ExampleFormView(
           key: args.key,
           clashableOne: args.clashableOne,
         ),
-        maintainState: false,
       );
     },
     NonReactiveViewRoute.name: (routeData) {
       return _i12.CustomPage<dynamic>(
         routeData: routeData,
-        child: const _i7.NonReactiveView(),
+        child: const _i6.NonReactiveView(),
         transitionsBuilder: _i14.CustomRouteTransition.sharedAxis,
         opaque: true,
         barrierDismissible: false,
       );
     },
-    HistoryViewRoute.name: (routeData) {
-      return _i12.CustomPage<dynamic>(
-        routeData: routeData,
-        child: const _i8.HistoryView(),
-        opaque: true,
-        barrierDismissible: false,
-      );
-    },
     FavoritesViewRoute.name: (routeData) {
       final args = routeData.argsAs<FavoritesViewArgs>(
           orElse: () => const FavoritesViewArgs());
       return _i12.AdaptivePage<dynamic>(
         routeData: routeData,
-        child: _i9.FavoritesView(
+        child: _i7.FavoritesView(
           key: args.key,
           id: args.id,
         ),
         opaque: true,
       );
     },
+    HistoryViewRoute.name: (routeData) {
+      return _i12.CustomPage<dynamic>(
+        routeData: routeData,
+        child: const _i8.HistoryView(),
+        opaque: true,
+        barrierDismissible: false,
+      );
+    },
     ProfileViewRoute.name: (routeData) {
       return _i12.CupertinoPageX<dynamic>(
         routeData: routeData,
-        child: const _i10.ProfileView(),
-        maintainState: false,
+        child: const _i9.ProfileView(),
       );
     },
     MultipleFuturesExampleViewRoute.name: (routeData) {
       return _i12.MaterialPageX<dynamic>(
         routeData: routeData,
-        child: const _i11.MultipleFuturesExampleView(),
-        maintainState: false,
+        child: const _i10.MultipleFuturesExampleView(),
       );
     },
   };
@@ -146,11 +133,6 @@ class StackedRouterWeb extends _i12.RootStackRouter {
               redirectTo: 'favorites',
               fullMatch: true,
             ),
-            _i12.RouteConfig(
-              HistoryViewRoute.name,
-              path: 'history-view',
-              parent: BottomNavExampleRoute.name,
-            ),
             _i12.RouteConfig(
               FavoritesViewRoute.name,
               path: 'favourites',
@@ -168,6 +150,11 @@ class StackedRouterWeb extends _i12.RootStackRouter {
                 ),
               ],
             ),
+            _i12.RouteConfig(
+              HistoryViewRoute.name,
+              path: 'history-view',
+              parent: BottomNavExampleRoute.name,
+            ),
             _i12.RouteConfig(
               ProfileViewRoute.name,
               path: 'profile-view',
@@ -198,9 +185,9 @@ class HomeViewRoute extends _i12.PageRouteInfo<HomeViewArgs> {
     String? title = 'hello',
     bool? isLoggedIn = false,
     _i15.Clashable Function(String)? clashableGetter,
-    List<_i3.HomeType> homeTypes = const [
-      _i3.HomeType.apartment,
-      _i3.HomeType.house
+    List<_i1.HomeType> homeTypes = const [
+      _i1.HomeType.apartment,
+      _i1.HomeType.house
     ],
   }) : super(
           HomeViewRoute.name,
@@ -223,7 +210,7 @@ class HomeViewArgs {
     this.title = 'hello',
     this.isLoggedIn = false,
     this.clashableGetter,
-    this.homeTypes = const [_i3.HomeType.apartment, _i3.HomeType.house],
+    this.homeTypes = const [_i1.HomeType.apartment, _i1.HomeType.house],
   });
 
   final _i13.Key? key;
@@ -234,7 +221,7 @@ class HomeViewArgs {
 
   final _i15.Clashable Function(String)? clashableGetter;
 
-  final List<_i3.HomeType> homeTypes;
+  final List<_i1.HomeType> homeTypes;
 
   @override
   String toString() {
@@ -243,7 +230,7 @@ class HomeViewArgs {
 }
 
 /// generated route for
-/// [_i4.BottomNavExample]
+/// [_i3.BottomNavExample]
 class BottomNavExampleRoute extends _i12.PageRouteInfo<void> {
   const BottomNavExampleRoute({List<_i12.PageRouteInfo>? children})
       : super(
@@ -256,7 +243,7 @@ class BottomNavExampleRoute extends _i12.PageRouteInfo<void> {
 }
 
 /// generated route for
-/// [_i5.StreamCounterView]
+/// [_i4.StreamCounterView]
 class StreamCounterViewRoute extends _i12.PageRouteInfo<StreamCounterViewArgs> {
   StreamCounterViewRoute({
     _i13.Key? key,
@@ -290,7 +277,7 @@ class StreamCounterViewArgs {
 }
 
 /// generated route for
-/// [_i6.ExampleFormView]
+/// [_i5.ExampleFormView]
 class ExampleFormViewRoute extends _i12.PageRouteInfo<ExampleFormViewArgs> {
   ExampleFormViewRoute({
     _i13.Key? key,
@@ -324,7 +311,7 @@ class ExampleFormViewArgs {
 }
 
 /// generated route for
-/// [_i7.NonReactiveView]
+/// [_i6.NonReactiveView]
 class NonReactiveViewRoute extends _i12.PageRouteInfo<void> {
   const NonReactiveViewRoute()
       : super(
@@ -336,19 +323,7 @@ class NonReactiveViewRoute extends _i12.PageRouteInfo<void> {
 }
 
 /// generated route for
-/// [_i8.HistoryView]
-class HistoryViewRoute extends _i12.PageRouteInfo<void> {
-  const HistoryViewRoute()
-      : super(
-          HistoryViewRoute.name,
-          path: 'history-view',
-        );
-
-  static const String name = 'HistoryView';
-}
-
-/// generated route for
-/// [_i9.FavoritesView]
+/// [_i7.FavoritesView]
 class FavoritesViewRoute extends _i12.PageRouteInfo<FavoritesViewArgs> {
   FavoritesViewRoute({
     _i13.Key? key,
@@ -384,7 +359,19 @@ class FavoritesViewArgs {
 }
 
 /// generated route for
-/// [_i10.ProfileView]
+/// [_i8.HistoryView]
+class HistoryViewRoute extends _i12.PageRouteInfo<void> {
+  const HistoryViewRoute()
+      : super(
+          HistoryViewRoute.name,
+          path: 'history-view',
+        );
+
+  static const String name = 'HistoryView';
+}
+
+/// generated route for
+/// [_i9.ProfileView]
 class ProfileViewRoute extends _i12.PageRouteInfo<void> {
   const ProfileViewRoute()
       : super(
@@ -396,7 +383,7 @@ class ProfileViewRoute extends _i12.PageRouteInfo<void> {
 }
 
 /// generated route for
-/// [_i11.MultipleFuturesExampleView]
+/// [_i10.MultipleFuturesExampleView]
 class MultipleFuturesExampleViewRoute extends _i12.PageRouteInfo<void> {
   const MultipleFuturesExampleViewRoute()
       : super(
@@ -406,3 +393,247 @@ class MultipleFuturesExampleViewRoute extends _i12.PageRouteInfo<void> {
 
   static const String name = 'MultipleFuturesExampleView';
 }
+
+extension RouterStateExtension on _i11.RouterService {
+  Future<dynamic> navigateToHomeView({
+    _i13.Key? key,
+    String? title = 'hello',
+    bool? isLoggedIn = false,
+    _i15.Clashable Function(String)? clashableGetter,
+    List<_i1.HomeType> homeTypes = const [
+      _i1.HomeType.apartment,
+      _i1.HomeType.house
+    ],
+    void Function(_i12.NavigationFailure)? onFailure,
+  }) async {
+    return navigateTo(
+      HomeViewRoute(
+        key: key,
+        title: title,
+        isLoggedIn: isLoggedIn,
+        clashableGetter: clashableGetter,
+        homeTypes: homeTypes,
+      ),
+      onFailure: onFailure,
+    );
+  }
+
+  Future<dynamic> navigateToBottomNavExample(
+      {void Function(_i12.NavigationFailure)? onFailure}) async {
+    return navigateTo(
+      const BottomNavExampleRoute(),
+      onFailure: onFailure,
+    );
+  }
+
+  Future<dynamic> navigateToStreamCounterView({
+    _i13.Key? key,
+    required List<_i16.Clashable> clashableTwo,
+    void Function(_i12.NavigationFailure)? onFailure,
+  }) async {
+    return navigateTo(
+      StreamCounterViewRoute(
+        key: key,
+        clashableTwo: clashableTwo,
+      ),
+      onFailure: onFailure,
+    );
+  }
+
+  Future<dynamic> navigateToExampleFormView({
+    _i13.Key? key,
+    required _i15.Clashable clashableOne,
+    void Function(_i12.NavigationFailure)? onFailure,
+  }) async {
+    return navigateTo(
+      ExampleFormViewRoute(
+        key: key,
+        clashableOne: clashableOne,
+      ),
+      onFailure: onFailure,
+    );
+  }
+
+  Future<dynamic> navigateToNonReactiveView(
+      {void Function(_i12.NavigationFailure)? onFailure}) async {
+    return navigateTo(
+      const NonReactiveViewRoute(),
+      onFailure: onFailure,
+    );
+  }
+
+  Future<dynamic> navigateToFavoritesView({
+    _i13.Key? key,
+    String? id,
+    void Function(_i12.NavigationFailure)? onFailure,
+  }) async {
+    return navigateTo(
+      FavoritesViewRoute(
+        key: key,
+        id: id,
+      ),
+      onFailure: onFailure,
+    );
+  }
+
+  Future<dynamic> navigateToHistoryView(
+      {void Function(_i12.NavigationFailure)? onFailure}) async {
+    return navigateTo(
+      const HistoryViewRoute(),
+      onFailure: onFailure,
+    );
+  }
+
+  Future<dynamic> navigateToProfileView(
+      {void Function(_i12.NavigationFailure)? onFailure}) async {
+    return navigateTo(
+      const ProfileViewRoute(),
+      onFailure: onFailure,
+    );
+  }
+
+  Future<dynamic> navigateToMultipleFuturesExampleView({
+    _i13.Key? key,
+    String? id,
+    void Function(_i12.NavigationFailure)? onFailure,
+  }) async {
+    return navigateTo(
+      FavoritesViewRoute(
+        id: id,
+        children: List.from([
+          MultipleFuturesExampleViewRoute(),
+        ]),
+      ),
+      onFailure: onFailure,
+    );
+  }
+
+  // Future<dynamic> navigateToHistoryView({
+  //   _i13.Key? key,
+  //   String? id,
+  //   void Function(_i12.NavigationFailure)? onFailure,
+  // }) async {
+  //   return navigateTo(
+  //     FavoritesViewRoute(
+  //       id: id,
+  //       children: List.from([
+  //         HistoryViewRoute(),
+  //       ]),
+  //     ),
+  //     onFailure: onFailure,
+  //   );
+  // }
+
+  Future<dynamic> replaceWithHomeView({
+    _i13.Key? key,
+    String? title = 'hello',
+    bool? isLoggedIn = false,
+    _i15.Clashable Function(String)? clashableGetter,
+    List<_i1.HomeType> homeTypes = const [
+      _i1.HomeType.apartment,
+      _i1.HomeType.house
+    ],
+    void Function(_i12.NavigationFailure)? onFailure,
+  }) async {
+    return replaceWith(
+      HomeViewRoute(
+        key: key,
+        title: title,
+        isLoggedIn: isLoggedIn,
+        clashableGetter: clashableGetter,
+        homeTypes: homeTypes,
+      ),
+      onFailure: onFailure,
+    );
+  }
+
+  Future<dynamic> replaceWithBottomNavExample(
+      {void Function(_i12.NavigationFailure)? onFailure}) async {
+    return replaceWith(
+      const BottomNavExampleRoute(),
+      onFailure: onFailure,
+    );
+  }
+
+  Future<dynamic> replaceWithStreamCounterView({
+    _i13.Key? key,
+    required List<_i16.Clashable> clashableTwo,
+    void Function(_i12.NavigationFailure)? onFailure,
+  }) async {
+    return replaceWith(
+      StreamCounterViewRoute(
+        key: key,
+        clashableTwo: clashableTwo,
+      ),
+      onFailure: onFailure,
+    );
+  }
+
+  Future<dynamic> replaceWithExampleFormView({
+    _i13.Key? key,
+    required _i15.Clashable clashableOne,
+    void Function(_i12.NavigationFailure)? onFailure,
+  }) async {
+    return replaceWith(
+      ExampleFormViewRoute(
+        key: key,
+        clashableOne: clashableOne,
+      ),
+      onFailure: onFailure,
+    );
+  }
+
+  Future<dynamic> replaceWithNonReactiveView(
+      {void Function(_i12.NavigationFailure)? onFailure}) async {
+    return replaceWith(
+      const NonReactiveViewRoute(),
+      onFailure: onFailure,
+    );
+  }
+
+  Future<dynamic> replaceWithFavoritesView({
+    _i13.Key? key,
+    String? id,
+    void Function(_i12.NavigationFailure)? onFailure,
+  }) async {
+    return replaceWith(
+      FavoritesViewRoute(
+        key: key,
+        id: id,
+      ),
+      onFailure: onFailure,
+    );
+  }
+
+  Future<dynamic> replaceWithHistoryView(
+      {void Function(_i12.NavigationFailure)? onFailure}) async {
+    return replaceWith(
+      const HistoryViewRoute(),
+      onFailure: onFailure,
+    );
+  }
+
+  Future<dynamic> replaceWithProfileView(
+      {void Function(_i12.NavigationFailure)? onFailure}) async {
+    return replaceWith(
+      const ProfileViewRoute(),
+      onFailure: onFailure,
+    );
+  }
+
+  Future<dynamic> replaceWithMultipleFuturesExampleView(
+      {void Function(_i12.NavigationFailure)? onFailure}) async {
+    return replaceWith(
+      const MultipleFuturesExampleViewRoute(),
+      onFailure: onFailure,
+    );
+  }
+
+  // Future<dynamic> replaceWithHistoryView(
+  //     {void Function(_i12.NavigationFailure)? onFailure}) async {
+  //   return replaceWith(
+  //     const HistoryViewRoute(),
+  //     onFailure: onFailure,
+  //   );
+  // }
+}
diff --git a/example/router_example/lib/ui/bottom_nav/bottom_nav_example_viewmodel.dart b/example/router_example/lib/ui/bottom_nav/bottom_nav_example_viewmodel.dart
index 1735f6c0f..1e347ef5d 100644
--- a/example/router_example/lib/ui/bottom_nav/bottom_nav_example_viewmodel.dart
+++ b/example/router_example/lib/ui/bottom_nav/bottom_nav_example_viewmodel.dart
@@ -8,24 +8,22 @@ class BottomNavExampleViewModel extends IndexTrackingViewModel {
   final log = getLogger('BottomNavExampleViewModel');
   final _routerService = exampleLocator<RouterService>();
 
+  BottomNavExampleViewModel() {
+    setCurrentWebPageIndex(_routerService);
+  }
+
   void handleNavigation(int index) {
     log.i('handleNavigation: $index');
     setIndex(index);
     switch (index) {
       case 0:
-        _routerService.navigateTo(
-          FavoritesViewRoute(),
-        );
+        _routerService.navigateTo(FavoritesViewRoute());
         break;
       case 1:
-        _routerService.navigateTo(
-          const HistoryViewRoute(),
-        );
+        _routerService.navigateTo(const HistoryViewRoute());
         break;
       case 2:
-        _routerService.navigateTo(
-          const ProfileViewRoute(),
-        );
+        _routerService.navigateTo(const ProfileViewRoute());
         break;
       default:
     }
diff --git a/example/router_example/lib/ui/drop_down_menu_from/select_location_view.form.dart b/example/router_example/lib/ui/drop_down_menu_from/select_location_view.form.dart
index abfca4e5c..00a859056 100644
--- a/example/router_example/lib/ui/drop_down_menu_from/select_location_view.form.dart
+++ b/example/router_example/lib/ui/drop_down_menu_from/select_location_view.form.dart
@@ -28,15 +28,17 @@ final Map<String, String> ProvinceValueToTitleMap = {
   'North West': 'North West',
 };
 
-mixin $SelectLocationView on StatelessWidget {
+mixin $SelectLocationView {
   /// Registers a listener on every generated controller that calls [model.setData()]
   /// with the latest textController values
   void syncFormWithViewModel(FormViewModel model) {}
 
   /// Registers a listener on every generated controller that calls [model.setData()]
   /// with the latest textController values
-  @Deprecated('Use syncFormWithViewModel instead.'
-      'This feature was deprecated after 3.1.0.')
+  @Deprecated(
+    'Use syncFormWithViewModel instead.'
+    'This feature was deprecated after 3.1.0.',
+  )
   void listenToFormUpdated(FormViewModel model) {}
 
   /// Calls dispose on all the generated controllers and focus nodes
@@ -63,7 +65,6 @@ extension ValueProperties on FormViewModel {
       this.fieldsValidationMessages[CountryValueKey];
   String? get provinceValidationMessage =>
       this.fieldsValidationMessages[ProvinceValueKey];
-  void clearForm() {}
 }
 
 extension Methods on FormViewModel {
@@ -79,4 +80,7 @@ extension Methods on FormViewModel {
       this.fieldsValidationMessages[CountryValueKey] = validationMessage;
   setProvinceValidationMessage(String? validationMessage) =>
       this.fieldsValidationMessages[ProvinceValueKey] = validationMessage;
+
+  /// Clears text input fields on the Form
+  void clearForm() {}
 }
diff --git a/example/router_example/lib/ui/form/example_form_view.form.dart b/example/router_example/lib/ui/form/example_form_view.form.dart
index 1ecd6e167..5f98d5f4b 100644
--- a/example/router_example/lib/ui/form/example_form_view.form.dart
+++ b/example/router_example/lib/ui/form/example_form_view.form.dart
@@ -34,7 +34,7 @@ final Map<String, String? Function(String?)?> _ExampleFormViewTextValidations =
   ShortBioValueKey: null,
 };
 
-mixin $ExampleFormView on StatelessWidget {
+mixin $ExampleFormView {
   TextEditingController get emailController =>
       _getFormTextEditingController(EmailValueKey, initialValue: 'Lorem');
   CustomEditingController get passwordController =>
@@ -59,11 +59,14 @@ mixin $ExampleFormView on StatelessWidget {
   FocusNode get passwordFocusNode => _getFormFocusNode(PasswordValueKey);
   FocusNode get shortBioFocusNode => _getFormFocusNode(ShortBioValueKey);
 
-  TextEditingController _getFormTextEditingController(String key,
-      {String? initialValue}) {
+  TextEditingController _getFormTextEditingController(
+    String key, {
+    String? initialValue,
+  }) {
     if (_ExampleFormViewTextEditingControllers.containsKey(key)) {
       return _ExampleFormViewTextEditingControllers[key]!;
     }
+
     _ExampleFormViewTextEditingControllers[key] =
         TextEditingController(text: initialValue);
     return _ExampleFormViewTextEditingControllers[key]!;
@@ -87,15 +90,17 @@ mixin $ExampleFormView on StatelessWidget {
 
   /// Registers a listener on every generated controller that calls [model.setData()]
   /// with the latest textController values
-  @Deprecated('Use syncFormWithViewModel instead.'
-      'This feature was deprecated after 3.1.0.')
+  @Deprecated(
+    'Use syncFormWithViewModel instead.'
+    'This feature was deprecated after 3.1.0.',
+  )
   void listenToFormUpdated(FormViewModel model) {
     emailController.addListener(() => _updateFormData(model));
     passwordController.addListener(() => _updateFormData(model));
     shortBioController.addListener(() => _updateFormData(model));
   }
 
-  final bool _autoTextFieldValidation = false;
+  static const bool _autoTextFieldValidation = false;
   bool validateFormFields(FormViewModel model) {
     _updateFormData(model, forceValidate: true);
     return model.isFormValid;
@@ -111,28 +116,12 @@ mixin $ExampleFormView on StatelessWidget {
           ShortBioValueKey: shortBioController.text,
         }),
     );
+
     if (_autoTextFieldValidation || forceValidate) {
-      _updateValidationData(model);
+      updateValidationData(model);
     }
   }
 
-  /// Updates the fieldsValidationMessages on the FormViewModel
-  void _updateValidationData(FormViewModel model) =>
-      model.setValidationMessages({
-        EmailValueKey: _getValidationMessage(EmailValueKey),
-        PasswordValueKey: _getValidationMessage(PasswordValueKey),
-        ShortBioValueKey: _getValidationMessage(ShortBioValueKey),
-      });
-
-  /// Returns the validation message for the given key
-  String? _getValidationMessage(String key) {
-    final validatorForKey = _ExampleFormViewTextValidations[key];
-    if (validatorForKey == null) return null;
-    String? validationMessageForKey =
-        validatorForKey(_ExampleFormViewTextEditingControllers[key]!.text);
-    return validationMessageForKey;
-  }
-
   /// Calls dispose on all the generated controllers and focus nodes
   void disposeForm() {
     // The dispose function for a TextEditingController sets all listeners to null
@@ -235,11 +224,6 @@ extension ValueProperties on FormViewModel {
       this.fieldsValidationMessages[BirthDateValueKey];
   String? get doYouLoveFoodValidationMessage =>
       this.fieldsValidationMessages[DoYouLoveFoodValueKey];
-  void clearForm() {
-    emailValue = '';
-    passwordValue = '';
-    shortBioValue = '';
-  }
 }
 
 extension Methods on FormViewModel {
@@ -274,4 +258,39 @@ extension Methods on FormViewModel {
       this.fieldsValidationMessages[BirthDateValueKey] = validationMessage;
   setDoYouLoveFoodValidationMessage(String? validationMessage) =>
       this.fieldsValidationMessages[DoYouLoveFoodValueKey] = validationMessage;
+
+  /// Clears text input fields on the Form
+  void clearForm() {
+    emailValue = '';
+    passwordValue = '';
+    shortBioValue = '';
+  }
+
+  /// Validates text input fields on the Form
+  void validateForm() {
+    this.setValidationMessages({
+      EmailValueKey: getValidationMessage(EmailValueKey),
+      PasswordValueKey: getValidationMessage(PasswordValueKey),
+      ShortBioValueKey: getValidationMessage(ShortBioValueKey),
+    });
+  }
 }
+
+/// Returns the validation message for the given key
+String? getValidationMessage(String key) {
+  final validatorForKey = _ExampleFormViewTextValidations[key];
+  if (validatorForKey == null) return null;
+
+  String? validationMessageForKey = validatorForKey(
+    _ExampleFormViewTextEditingControllers[key]!.text,
+  );
+
+  return validationMessageForKey;
+}
+
+/// Updates the fieldsValidationMessages on the FormViewModel
+void updateValidationData(FormViewModel model) => model.setValidationMessages({
+      EmailValueKey: getValidationMessage(EmailValueKey),
+      PasswordValueKey: getValidationMessage(PasswordValueKey),
+      ShortBioValueKey: getValidationMessage(ShortBioValueKey),
+    });
diff --git a/example/router_example/pubspec.yaml b/example/router_example/pubspec.yaml
index 0c04873dd..634d650f3 100644
--- a/example/router_example/pubspec.yaml
+++ b/example/router_example/pubspec.yaml
@@ -23,7 +23,7 @@ dependencies:
 
   # The following adds the Cupertino Icons font to your application.
   # Use with the CupertinoIcons class for iOS style icons.
-  cupertino_icons: ^0.1.2
+  cupertino_icons: ^1.0.2
 
   # state management
   stacked:
diff --git a/lib/src/router/router_service_interface.dart b/lib/src/router/router_service_interface.dart
new file mode 100644
index 000000000..9b5bf9209
--- /dev/null
+++ b/lib/src/router/router_service_interface.dart
@@ -0,0 +1,7 @@
+import 'package:stacked/stacked.dart';
+
+abstract class RouterServiceInterface {
+  RootStackRouter get router;
+
+  RouteData get topRoute;
+}
diff --git a/lib/src/view_models/index_tracking_viewmodel.dart b/lib/src/view_models/index_tracking_viewmodel.dart
index 8ff621b06..552fe8854 100644
--- a/lib/src/view_models/index_tracking_viewmodel.dart
+++ b/lib/src/view_models/index_tracking_viewmodel.dart
@@ -1,4 +1,5 @@
 import 'package:stacked/src/mixins/listenable_service_mixin.dart';
+import 'package:stacked/src/router/router_service_interface.dart';
 import 'package:stacked/src/view_models/base_view_models.dart';
 
 /// You can use [BaseViewModel] or [ReactiveViewModel] with a [IndexTrackingStateHelper]
@@ -27,4 +28,37 @@ class IndexTrackingViewModel extends ReactiveViewModel {
 
   @override
   List<ListenableServiceMixin> get listenableServices => [];
+
+  /// Sets current index using current Route on Web Platform.
+  ///
+  /// Allows to get the index from url during a browser refresh which means the
+  /// app starts from scracth.
+  void setCurrentWebPageIndex(RouterServiceInterface service) {
+    if (!service.topRoute.hasPendingChildren) return;
+
+    int? currentWebPageIndex;
+
+    try {
+      currentWebPageIndex = service.router.routes
+          .firstWhere(
+            (route) => route.name == service.topRoute.name,
+          )
+          .children
+          ?.routes
+          .skipWhile((route) => route.name.startsWith('#'))
+          .toList()
+          .indexWhere(
+            (route) =>
+                route.name == service.topRoute.pendingChildren.first.name,
+          );
+    } on StateError catch (_) {
+      /// The route does not meet the condition in the firstWhere call
+    } catch (_) {
+      /// Catch everything else
+    }
+
+    if (currentWebPageIndex == null || currentWebPageIndex == -1) return;
+
+    setIndex(currentWebPageIndex);
+  }
 }
diff --git a/lib/src/view_models/view_model_builder.dart b/lib/src/view_models/view_model_builder.dart
index f53fa6bd6..044ebcb6f 100644
--- a/lib/src/view_models/view_model_builder.dart
+++ b/lib/src/view_models/view_model_builder.dart
@@ -69,7 +69,7 @@ class ViewModelBuilder<T extends ChangeNotifier> extends StatefulWidget {
     this.createNewViewModelOnInsert = false,
     this.fireOnViewModelReadyOnce = false,
     @Deprecated('Prefer to use fireOnViewModelReadyOnce')
-        this.fireOnModelReadyOnce = false,
+    this.fireOnModelReadyOnce = false,
     this.initialiseSpecialViewModelsOnce = false,
     Key? key,
   })  : providerType = ViewModelBuilderType.nonReactive,
@@ -88,7 +88,7 @@ class ViewModelBuilder<T extends ChangeNotifier> extends StatefulWidget {
     this.createNewViewModelOnInsert = false,
     this.fireOnViewModelReadyOnce = false,
     @Deprecated('Prefer to use fireOnViewModelReadyOnce')
-        this.fireOnModelReadyOnce = false,
+    this.fireOnModelReadyOnce = false,
     this.initialiseSpecialViewModelsOnce = false,
     Key? key,
   })  : providerType = ViewModelBuilderType.reactive,
diff --git a/lib/stacked.dart b/lib/stacked.dart
index 9a1bf7f4a..48b11e8f9 100644
--- a/lib/stacked.dart
+++ b/lib/stacked.dart
@@ -19,6 +19,7 @@ export 'src/router/controller/routing_controller.dart';
 /// Navigator 2.0 Exports
 export 'src/router/matcher/route_match.dart';
 export 'src/router/navigation_failure.dart';
+export 'src/router/router_service_interface.dart';
 export 'src/router/parser/route_information_parser.dart';
 export 'src/router/route/page_route_info.dart';
 export 'src/router/route/route_config.dart';


Test patch:
diff --git a/test/index_tracking_viewmodel_test.dart b/test/index_tracking_viewmodel_test.dart
index 0cc877675..19e8e02cf 100644
--- a/test/index_tracking_viewmodel_test.dart
+++ b/test/index_tracking_viewmodel_test.dart
@@ -1,20 +1,170 @@
+import 'package:flutter/foundation.dart';
 import 'package:flutter_test/flutter_test.dart';
+import 'package:stacked/src/router/matcher/route_matcher.dart';
 import 'package:stacked/stacked.dart';
 
 class TestIndexTrackingViewModel extends BaseViewModel
     with IndexTrackingStateHelper {}
 
+class TestRouterService implements RouterServiceInterface {
+  final RootStackRouter testRouter;
+  final RouteData testTopRoute;
+  const TestRouterService({
+    required this.testRouter,
+    required this.testTopRoute,
+  });
+
+  @override
+  RootStackRouter get router => testRouter;
+
+  @override
+  RouteData get topRoute => testTopRoute;
+}
+
+class TestRouter extends RootStackRouter {
+  final Map<String, PageFactory> testPagesMap;
+  final List<RouteConfig> testRoutes;
+  TestRouter({this.testPagesMap = const {}, this.testRoutes = const []});
+
+  @override
+  Map<String, PageFactory> get pagesMap => testPagesMap;
+
+  @override
+  List<RouteConfig> get routes => testRoutes;
+}
+
+class TestRoutingController extends RoutingController {
+  @override
+  bool canPop({
+    bool ignoreChildRoutes = false,
+    bool ignoreParentRoutes = false,
+    bool ignorePagelessRoutes = false,
+  }) {
+    // TODO: implement canPop
+    throw UnimplementedError();
+  }
+
+  @override
+  // TODO: implement canPopSelfOrChildren
+  bool get canPopSelfOrChildren => throw UnimplementedError();
+
+  @override
+  // TODO: implement current
+  RouteData get current => throw UnimplementedError();
+
+  @override
+  // TODO: implement currentChild
+  RouteData? get currentChild => throw UnimplementedError();
+
+  @override
+  // TODO: implement key
+  LocalKey get key => throw UnimplementedError();
+
+  @override
+  // TODO: implement managedByWidget
+  bool get managedByWidget => throw UnimplementedError();
+
+  @override
+  // TODO: implement matcher
+  RouteMatcher get matcher => throw UnimplementedError();
+
+  @override
+  // TODO: implement pageBuilder
+  PageBuilder get pageBuilder => throw UnimplementedError();
+
+  @override
+  Future<bool> pop<T extends Object?>([T? result]) {
+    // TODO: implement pop
+    throw UnimplementedError();
+  }
+
+  @override
+  // TODO: implement routeCollection
+  RouteCollection get routeCollection => throw UnimplementedError();
+
+  @override
+  // TODO: implement routeData
+  RouteData get routeData => throw UnimplementedError();
+
+  @override
+  // TODO: implement stack
+  List<StackedPage> get stack => throw UnimplementedError();
+
+  @override
+  RoutingController topMostRouter({bool ignorePagelessRoutes = false}) {
+    // TODO: implement topMostRouter
+    throw UnimplementedError();
+  }
+
+  @override
+  void updateRouteData(RouteData data) {
+    // TODO: implement updateRouteData
+  }
+}
+
+final bottomNavExampleRouteMatch = RouteMatch(
+  key: UniqueKey(),
+  name: 'BottomNavExample',
+  path: 'bottom-nav-example',
+  segments: const [],
+  stringMatch: '',
+);
+
+final favoriteRouteMatch = RouteMatch(
+  key: UniqueKey(),
+  name: 'FavoriteView',
+  path: 'favorite-view',
+  segments: const [],
+  stringMatch: '',
+);
+
+final historyRouteMatch = RouteMatch(
+  key: UniqueKey(),
+  name: 'HistoryView',
+  path: 'history-view',
+  segments: const [],
+  stringMatch: '',
+);
+
+final profileRouteMatch = RouteMatch(
+  key: UniqueKey(),
+  name: 'ProfileView',
+  path: 'profile-view',
+  segments: const [],
+  stringMatch: '',
+);
+
+RouteData getBottomNavExampleRouteData({
+  List<RouteMatch> pendingChildren = const [],
+}) =>
+    RouteData(
+      route: bottomNavExampleRouteMatch,
+      router: TestRoutingController(),
+      pendingChildren: pendingChildren,
+    );
+
+RouteConfig getRouteConfig(String name, {List<RouteConfig>? children}) =>
+    RouteConfig(
+      name,
+      path: toSnakeCase(name),
+      children: children,
+    );
+
+String toSnakeCase(String text) {
+  return text.replaceAll(RegExp(r'(?<!^)(?=[A-Z])'), r"_").toLowerCase();
+}
+
 void main() {
   group('IndexTrackingViewmodelTest -', () {
     group('setIndex -', () {
       test('When called with 1, should set currentIndex to 1', () {
-        var viewModel = TestIndexTrackingViewModel();
+        final viewModel = TestIndexTrackingViewModel();
         viewModel.setIndex(1);
         expect(viewModel.currentIndex, 1);
       });
 
       test('When called with 1, should notifyListeners about update', () {
-        var viewModel = TestIndexTrackingViewModel();
+        final viewModel = TestIndexTrackingViewModel();
         var called = false;
         viewModel.addListener(() {
           called = true;
@@ -26,7 +176,7 @@ void main() {
       test(
           'When called with 1 and currentIndex was 0, reverse should return false',
           () {
-        var viewModel = TestIndexTrackingViewModel();
+        final viewModel = TestIndexTrackingViewModel();
         viewModel.setIndex(1);
         expect(viewModel.reverse, false);
       });
@@ -34,7 +184,7 @@ void main() {
       test(
           'When called with 0 and currentIndex was 1, reverse should return true',
           () {
-        var viewModel = TestIndexTrackingViewModel();
+        final viewModel = TestIndexTrackingViewModel();
         viewModel.setIndex(1);
 
         viewModel.setIndex(0);
@@ -42,16 +192,239 @@ void main() {
       });
 
       test('When called with 1 isIndexSelected should return false for 0', () {
-        var model = TestIndexTrackingViewModel();
+        final model = TestIndexTrackingViewModel();
         model.setIndex(1);
         expect(model.isIndexSelected(0), false);
       });
 
       test('When called with 1 isIndexSelected should return true for 1', () {
-        var viewModel = TestIndexTrackingViewModel();
+        final viewModel = TestIndexTrackingViewModel();
         viewModel.setIndex(1);
         expect(viewModel.isIndexSelected(1), true);
       });
     });
+
+    group('setCurrentWebPageIndex -', () {
+      test('When pendingChildren is empty should NOT change currentIndex', () {
+        final service = TestRouterService(
+          testRouter: TestRouter(),
+          testTopRoute: getBottomNavExampleRouteData(),
+        );
+        final viewModel = IndexTrackingViewModel();
+        viewModel.setIndex(0);
+
+        viewModel.setCurrentWebPageIndex(service);
+
+        expect(viewModel.currentIndex, 0);
+      });
+
+      test('When pendingChildren is empty should NOT call notifyListeners', () {
+        final service = TestRouterService(
+          testRouter: TestRouter(),
+          testTopRoute: getBottomNavExampleRouteData(),
+        );
+        final viewModel = IndexTrackingViewModel();
+        var called = 0;
+        viewModel.addListener(() {
+          called++;
+        });
+
+        viewModel.setCurrentWebPageIndex(service);
+
+        expect(called, 0);
+      });
+
+      test(
+          'When topRoute is NOT find on routes should NOT call notifyListeners',
+          () {
+        final service = TestRouterService(
+          testRouter: TestRouter(testRoutes: [
+            getRouteConfig('HomeView'),
+            getRouteConfig('StreamsView'),
+            getRouteConfig('CounterView'),
+          ]),
+          testTopRoute: getBottomNavExampleRouteData(
+            pendingChildren: [
+              favoriteRouteMatch,
+              historyRouteMatch,
+              profileRouteMatch,
+            ],
+          ),
+        );
+        final viewModel = IndexTrackingViewModel();
+        var called = 0;
+        viewModel.addListener(() {
+          called++;
+        });
+
+        viewModel.setCurrentWebPageIndex(service);
+
+        expect(called, 0);
+      });
+
+      test(
+          'When topRoute is find on routes and route has NO children should NOT call notifyListeners',
+          () {
+        final service = TestRouterService(
+          testRouter: TestRouter(testRoutes: [
+            getRouteConfig('HomeView'),
+            getRouteConfig('StreamsView'),
+            getRouteConfig('BottomNavExample'),
+            getRouteConfig('CounterView'),
+          ]),
+          testTopRoute: getBottomNavExampleRouteData(
+            pendingChildren: [
+              favoriteRouteMatch,
+              historyRouteMatch,
+              profileRouteMatch,
+            ],
+          ),
+        );
+        final viewModel = IndexTrackingViewModel();
+        var called = 0;
+        viewModel.addListener(() {
+          called++;
+        });
+
+        viewModel.setCurrentWebPageIndex(service);
+
+        expect(called, 0);
+      });
+
+      test(
+          'When topRoute is in the routes, the route has NOT a match in the children should NOT call notifyListeners',
+          () {
+        final service = TestRouterService(
+          testRouter: TestRouter(testRoutes: [
+            getRouteConfig('HomeView'),
+            getRouteConfig('StreamsView'),
+            getRouteConfig('BottomNavExample', children: [
+              getRouteConfig('FavoriteView'),
+              getRouteConfig('ProfileView'),
+            ]),
+            getRouteConfig('CounterView'),
+          ]),
+          testTopRoute: getBottomNavExampleRouteData(
+            pendingChildren: [historyRouteMatch],
+          ),
+        );
+        final viewModel = IndexTrackingViewModel();
+        var called = 0;
+        viewModel.addListener(() {
+          called++;
+        });
+
+        viewModel.setCurrentWebPageIndex(service);
+
+        expect(called, 0);
+      });
+
+      test(
+          'When topRoute is in the routes, the route has a match in the children should call notifyListeners',
+          () {
+        final service = TestRouterService(
+          testRouter: TestRouter(testRoutes: [
+            getRouteConfig('HomeView'),
+            getRouteConfig('StreamsView'),
+            getRouteConfig('BottomNavExample', children: [
+              getRouteConfig('FavoriteView'),
+              getRouteConfig('HistoryView'),
+              getRouteConfig('ProfileView'),
+            ]),
+            getRouteConfig('CounterView'),
+          ]),
+          testTopRoute: getBottomNavExampleRouteData(
+            pendingChildren: [historyRouteMatch],
+          ),
+        );
+        final viewModel = IndexTrackingViewModel();
+        var called = 0;
+        viewModel.addListener(() {
+          called++;
+        });
+
+        viewModel.setCurrentWebPageIndex(service);
+
+        expect(called, 1);
+      });
+
+      test(
+          'When topRoute is in the routes, the route has a match in the children should change currentIndex to 0',
+          () {
+        final service = TestRouterService(
+          testRouter: TestRouter(testRoutes: [
+            getRouteConfig('HomeView'),
+            getRouteConfig('StreamsView'),
+            getRouteConfig('BottomNavExample', children: [
+              getRouteConfig('FavoriteView'),
+              getRouteConfig('HistoryView'),
+              getRouteConfig('ProfileView'),
+            ]),
+            getRouteConfig('CounterView'),
+          ]),
+          testTopRoute: getBottomNavExampleRouteData(
+            pendingChildren: [favoriteRouteMatch],
+          ),
+        );
+        final viewModel = IndexTrackingViewModel();
+        viewModel.setIndex(2);
+
+        viewModel.setCurrentWebPageIndex(service);
+
+        expect(viewModel.currentIndex, 0);
+      });
+
+      test(
+          'When topRoute is in the routes, the route has a match in the children should change currentIndex to 1',
+          () {
+        final service = TestRouterService(
+          testRouter: TestRouter(testRoutes: [
+            getRouteConfig('HomeView'),
+            getRouteConfig('StreamsView'),
+            getRouteConfig('BottomNavExample', children: [
+              getRouteConfig('FavoriteView'),
+              getRouteConfig('HistoryView'),
+              getRouteConfig('ProfileView'),
+            ]),
+            getRouteConfig('CounterView'),
+          ]),
+          testTopRoute: getBottomNavExampleRouteData(
+            pendingChildren: [historyRouteMatch],
+          ),
+        );
+        final viewModel = IndexTrackingViewModel();
+        viewModel.setIndex(0);
+
+        viewModel.setCurrentWebPageIndex(service);
+
+        expect(viewModel.currentIndex, 1);
+      });
+
+      test(
+          'When topRoute is in the routes, the route has a match in the children should change currentIndex to 2',
+          () {
+        final service = TestRouterService(
+          testRouter: TestRouter(testRoutes: [
+            getRouteConfig('HomeView'),
+            getRouteConfig('StreamsView'),
+            getRouteConfig('BottomNavExample', children: [
+              getRouteConfig('FavoriteView'),
+              getRouteConfig('HistoryView'),
+              getRouteConfig('ProfileView'),
+            ]),
+            getRouteConfig('CounterView'),
+          ]),
+          testTopRoute: getBottomNavExampleRouteData(
+            pendingChildren: [profileRouteMatch],
+          ),
+        );
+        final viewModel = IndexTrackingViewModel();
+        viewModel.setIndex(0);
+
+        viewModel.setCurrentWebPageIndex(service);
+
+        expect(viewModel.currentIndex, 2);
+      });
+    });
   });
 }