Basics

Router

Pendahuluan

Rute memungkinkan Anda mendefinisikan halaman-halaman berbeda di aplikasi Anda dan menavigasi di antaranya.

Gunakan rute ketika Anda perlu:

  • Mendefinisikan halaman yang tersedia di aplikasi Anda
  • Menavigasi pengguna antar layar
  • Melindungi halaman di balik autentikasi
  • Mengirim data dari satu halaman ke halaman lain
  • Menangani deep link dari URL

Anda dapat menambahkan rute di dalam file lib/routes/router.dart.

appRouter() => nyRoutes((router) {

  router.add(HomePage.path).initialRoute();

  router.add(PostsPage.path);

  router.add(PostDetailPage.path);

  // add more routes
  // router.add(AccountPage.path);

});

Tip: Anda dapat membuat rute secara manual atau menggunakan alat CLI Metro untuk membuatnya secara otomatis.

Berikut adalah contoh membuat halaman 'account' menggunakan Metro.

metro make:page account_page
// Adds your new route automatically to /lib/routes/router.dart
appRouter() => nyRoutes((router) {
  ...
  router.add(AccountPage.path);
});

Anda mungkin juga perlu mengirim data dari satu tampilan ke tampilan lainnya. Di Nylo Website, hal ini dimungkinkan menggunakan NyStatefulWidget (widget stateful dengan akses data rute bawaan). Kita akan membahas lebih dalam untuk menjelaskan cara kerjanya.

Menambahkan rute

Ini adalah cara termudah untuk menambahkan rute baru ke proyek Anda.

Jalankan perintah di bawah ini untuk membuat halaman baru.

metro make:page profile_page

Setelah menjalankan perintah di atas, akan dibuat Widget baru bernama ProfilePage dan ditambahkan ke direktori resources/pages/ Anda. Perintah ini juga akan menambahkan rute baru ke file lib/routes/router.dart Anda.

File: /lib/routes/router.dart

appRouter() => nyRoutes((router) {
  ...
  router.add(HomePage.path).initialRoute();

  // My new route
  router.add(ProfilePage.path);
});

Navigasi ke halaman

Anda dapat menavigasi ke halaman baru menggunakan helper routeTo.

void _pressedSettings() {
    routeTo(SettingsPage.path);
}

Rute awal

Di router Anda, Anda dapat mendefinisikan halaman pertama yang harus dimuat menggunakan metode .initialRoute().

Setelah Anda menetapkan rute awal, halaman tersebut akan menjadi halaman pertama yang dimuat saat Anda membuka aplikasi.

appRouter() => nyRoutes((router) {
  router.add(HomePage.path);

  router.add(SettingsPage.path);

  router.add(ProfilePage.path).initialRoute();
  // new initial route
});

Rute Awal Bersyarat

Anda juga dapat menetapkan rute awal bersyarat menggunakan parameter when:

appRouter() => nyRoutes((router) {
  router.add(OnboardingPage.path).initialRoute(
    when: () => !hasCompletedOnboarding()
  );

  router.add(HomePage.path).initialRoute(
    when: () => hasCompletedOnboarding()
  );
});

Navigasi ke Rute Awal

Gunakan routeToInitial() untuk menavigasi ke rute awal aplikasi:

void _goHome() {
    routeToInitial();
}

Ini akan menavigasi ke rute yang ditandai dengan .initialRoute() dan menghapus tumpukan navigasi.

Rute Pratinjau

Selama pengembangan, Anda mungkin ingin melihat pratinjau halaman tertentu dengan cepat tanpa mengubah rute awal secara permanen. Gunakan .previewRoute() untuk sementara menjadikan rute mana pun sebagai rute awal:

appRouter() => nyRoutes((router) {
  router.add(HomePage.path).initialRoute();

  router.add(SettingsPage.path);

  router.add(ProfilePage.path).previewRoute(); // This will be shown first during development
});

Metode previewRoute():

  • Menggantikan pengaturan initialRoute() dan authenticatedRoute() yang ada
  • Menjadikan rute yang ditentukan sebagai rute awal
  • Berguna untuk menguji halaman tertentu dengan cepat selama pengembangan

Peringatan: Ingat untuk menghapus .previewRoute() sebelum merilis aplikasi Anda!

Rute Terautentikasi

Di aplikasi Anda, Anda dapat mendefinisikan rute untuk menjadi rute awal ketika pengguna sudah terautentikasi. Ini akan secara otomatis menggantikan rute awal default dan menjadi halaman pertama yang dilihat pengguna saat mereka masuk.

Pertama, pengguna Anda harus masuk menggunakan helper Auth.authenticate({...}).

Sekarang, saat mereka membuka aplikasi, rute yang Anda definisikan akan menjadi halaman default sampai mereka keluar.

appRouter() => nyRoutes((router) {

  router.add(IntroPage.path).initialRoute();

  router.add(LoginPage.path);

  router.add(ProfilePage.path).authenticatedRoute();
  // auth page
});

Rute Terautentikasi Bersyarat

Anda juga dapat menetapkan rute terautentikasi bersyarat:

router.add(ProfilePage.path).authenticatedRoute(
  when: () => hasCompletedSetup()
);

Navigasi ke Rute Terautentikasi

Anda dapat menavigasi ke halaman terautentikasi menggunakan helper routeToAuthenticatedRoute():

routeToAuthenticatedRoute();

Lihat juga: Autentikasi untuk detail tentang mengautentikasi pengguna dan mengelola sesi.

Rute Tidak Dikenal

Anda dapat mendefinisikan rute untuk menangani skenario 404/tidak ditemukan menggunakan .unknownRoute():

appRouter() => nyRoutes((router) {
  router.add(HomePage.path).initialRoute();

  router.add(NotFoundPage.path).unknownRoute();
});

Ketika pengguna menavigasi ke rute yang tidak ada, mereka akan ditampilkan halaman rute tidak dikenal.

Route guards

Route guards melindungi halaman dari akses yang tidak sah. Mereka berjalan sebelum navigasi selesai, memungkinkan Anda mengalihkan pengguna atau memblokir akses berdasarkan kondisi.

Gunakan route guards ketika Anda perlu:

  • Melindungi halaman dari pengguna yang belum terautentikasi
  • Memeriksa izin sebelum mengizinkan akses
  • Mengalihkan pengguna berdasarkan kondisi (misalnya, onboarding belum selesai)
  • Mencatat atau melacak tampilan halaman

Untuk membuat Route Guard baru, jalankan perintah di bawah ini.

metro make:route_guard dashboard

Selanjutnya, tambahkan Route Guard baru ke rute Anda.

// File: /routes/router.dart
appRouter() => nyRoutes((router) {
  router.add(HomePage.path);

  router.add(LoginPage.path);

  router.add(DashboardPage.path,
    routeGuards: [
      DashboardRouteGuard() // Add your guard
    ]
  ); // restricted page
});

Anda juga dapat mengatur route guards menggunakan metode addRouteGuard:

// File: /routes/router.dart
appRouter() => nyRoutes((router) {
    router.add(DashboardPage.path)
            .addRouteGuard(MyRouteGuard());

    // or add multiple guards

    router.add(DashboardPage.path)
            .addRouteGuards([MyRouteGuard(), MyOtherRouteGuard()]);
})

Siklus Hidup NyRouteGuard

Di v7, route guards menggunakan kelas NyRouteGuard dengan tiga metode siklus hidup:

  • onBefore(RouteContext context) - Dipanggil sebelum navigasi. Kembalikan next() untuk melanjutkan, redirect() untuk pergi ke tempat lain, atau abort() untuk menghentikan.
  • onAfter(RouteContext context) - Dipanggil setelah navigasi berhasil ke rute.

Contoh Dasar

File: /routes/guards/dashboard_route_guard.dart

class DashboardRouteGuard extends NyRouteGuard {
  DashboardRouteGuard();

  @override
  Future<GuardResult> onBefore(RouteContext context) async {
    // Perform a check if they can access the page
    bool userLoggedIn = await Auth.isAuthenticated();

    if (userLoggedIn == false) {
      return redirect(LoginPage.path);
    }

    return next();
  }

  @override
  Future<void> onAfter(RouteContext context) async {
    // Track page view after successful navigation
    Analytics.trackPageView(context.routeName);
  }
}

RouteContext

Kelas RouteContext menyediakan akses ke informasi navigasi:

Properti Tipe Deskripsi
context BuildContext? Build context saat ini
data dynamic Data yang dikirim ke rute
queryParameters Map<String, String> Parameter query URL
routeName String Nama/path rute
originalRouteName String? Nama rute asli sebelum transformasi
@override
Future<GuardResult> onBefore(RouteContext context) async {
  print('Navigating to: ${context.routeName}');
  print('Query params: ${context.queryParameters}');
  print('Route data: ${context.data}');

  return next();
}

Metode Bantuan Guard

next()

Lanjutkan ke guard berikutnya atau ke rute:

@override
Future<GuardResult> onBefore(RouteContext context) async {
  return next(); // Allow navigation to continue
}

redirect()

Arahkan ulang ke rute yang berbeda:

@override
Future<GuardResult> onBefore(RouteContext context) async {
  if (!isLoggedIn) {
    return redirect(
      LoginPage.path,
      data: {'returnTo': context.routeName},
      navigationType: NavigationType.pushReplace,
    );
  }
  return next();
}

Metode redirect() menerima:

Parameter Tipe Deskripsi
path Object Path rute atau RouteView
data dynamic Data yang dikirim ke rute
queryParameters Map<String, dynamic>? Parameter query
navigationType NavigationType Tipe navigasi (default: pushReplace)
transitionType TransitionType? Transisi halaman
onPop Function(dynamic)? Callback saat rute di-pop

abort()

Hentikan navigasi tanpa pengalihan:

@override
Future<GuardResult> onBefore(RouteContext context) async {
  if (isMaintenanceMode) {
    showMaintenanceDialog();
    return abort(); // User stays on current route
  }
  return next();
}

setData()

Modifikasi data yang dikirim ke guard berikutnya dan rute:

@override
Future<GuardResult> onBefore(RouteContext context) async {
  final user = await fetchUser();
  setData({'user': user, ...?context.data});
  return next();
}

Guard Berparameter

Gunakan ParameterizedGuard ketika Anda perlu mengonfigurasi perilaku guard per rute:

class RoleGuard extends ParameterizedGuard<List<String>> {
  RoleGuard(super.params);

  @override
  Future<GuardResult> onBefore(RouteContext context) async {
    final user = await Auth.user();
    if (!params.any((role) => user.hasRole(role))) {
      return redirect('/unauthorized');
    }
    return next();
  }
}

// Usage:
router.add(AdminPage.path, routeGuards: [
  RoleGuard(['admin', 'moderator'])
]);

Guard Stacks

Gabungkan beberapa guard menjadi satu guard yang dapat digunakan kembali menggunakan GuardStack:

// Create reusable guard combinations
final adminGuards = GuardStack([
  AuthGuard(),
  RoleGuard(['admin']),
  AuditLogGuard(),
]);

router.add(AdminPage.path, routeGuards: [adminGuards]);

Guard Bersyarat

Terapkan guard secara bersyarat berdasarkan predikat:

router.add(DashboardPage.path, routeGuards: [
  ConditionalGuard(
    condition: (context) => context.routeName.startsWith('/admin'),
    guard: AdminGuard(),
  )
]);

Mengirim data ke halaman lain

Di bagian ini, kami akan menunjukkan bagaimana Anda dapat mengirim data dari satu widget ke widget lainnya.

Dari Widget Anda, gunakan helper routeTo dan kirim data yang ingin Anda kirim ke halaman baru.

// HomePage Widget
void _pressedSettings() {
    routeTo(SettingsPage.path, data: "Hello World");
}
...
// SettingsPage Widget (other page)
class _SettingsPageState extends NyPage<SettingsPage> {
  ...
  @override
  get init => () {
    print(widget.data()); // Hello World
    // or
    print(data()); // Hello World
  };

Contoh lainnya

// Home page widget
class _HomePageState extends NyPage<HomePage> {

  _showProfile() {
    User user = new User();
    user.firstName = 'Anthony';

    routeTo(ProfilePage.path, data: user);
  }

...

// Profile page widget (other page)
class _ProfilePageState extends NyPage<ProfilePage> {

  @override
  get init => () {
    User user = widget.data();
    print(user.firstName); // Anthony

  };

Grup Rute

Grup rute mengorganisir rute-rute terkait dan menerapkan pengaturan bersama. Mereka berguna ketika beberapa rute membutuhkan guard, prefix URL, atau gaya transisi yang sama.

Gunakan grup rute ketika Anda perlu:

  • Menerapkan route guard yang sama ke beberapa halaman
  • Menambahkan prefix URL ke sekumpulan rute (misalnya, /admin/...)
  • Mengatur transisi halaman yang sama untuk rute-rute terkait

Anda dapat mendefinisikan grup rute seperti pada contoh di bawah ini.

appRouter() => nyRoutes((router) {
  ...
  router.group(() => {
    "route_guards": [AuthRouteGuard()],
    "prefix": "/dashboard",
    "transition_type": TransitionType.fade(),
  }, (router) {
    router.add(ChatPage.path);

    router.add(FollowersPage.path);
  });

Pengaturan opsional untuk grup rute adalah:

Pengaturan Tipe Deskripsi
route_guards List<RouteGuard> Terapkan route guards ke semua rute dalam grup
prefix String Tambahkan prefix ke semua path rute dalam grup
transition_type TransitionType Atur transisi untuk semua rute dalam grup
transition PageTransitionType Atur tipe transisi halaman (tidak digunakan lagi, gunakan transition_type)
transition_settings PageTransitionSettings Atur pengaturan transisi

Menggunakan Parameter Rute

Ketika Anda membuat halaman baru, Anda dapat memperbarui rute untuk menerima parameter.

class ProfilePage extends NyStatefulWidget<HomeController> {
  static RouteView path = ("/profile/{userId}", (_) => ProfilePage());

  ProfilePage() : super(child: () => _ProfilePageState());
}

Sekarang, saat Anda menavigasi ke halaman tersebut, Anda dapat mengirim userId

routeTo(ProfilePage.path.withParams({"userId": 7}));

Anda dapat mengakses parameter di halaman baru seperti ini.

class _ProfilePageState extends NyPage<ProfilePage> {

  @override
  get init => () {
    print(widget.queryParameters()); // {"userId": 7}
  };
}

Query Parameters

Saat menavigasi ke halaman baru, Anda juga dapat memberikan query parameters.

Mari kita lihat.

  // Home page
  routeTo(ProfilePage.path, queryParameters: {"user": "7"});
  // navigate to profile page

  ...

  // Profile Page
  @override
  get init => () {
    print(widget.queryParameters()); // {"user": 7}
    // or
    print(queryParameters()); // {"user": 7}
  };

Catatan: Selama widget halaman Anda meng-extend NyStatefulWidget dan kelas NyPage, maka Anda dapat memanggil widget.queryParameters() untuk mengambil semua query parameters dari nama rute.

// Example page
routeTo(ProfilePage.path, queryParameters: {"hello": "world", "say": "I love code"});
...

// Home page
class MyHomePage extends NyStatefulWidget<HomeController> {
  ...
}

class _MyHomePageState extends NyPage<MyHomePage> {

  @override
  get init => () {
    widget.queryParameters(); // {"hello": "World", "say": "I love code"}
    // or
    queryParameters(); // {"hello": "World", "say": "I love code"}
  };

Tip: Query parameters harus mengikuti protokol HTTP, Contoh: /account?userId=1&tab=2

Transisi Halaman

Anda dapat menambahkan transisi saat menavigasi dari satu halaman dengan memodifikasi file router.dart Anda.

import 'package:page_transition/page_transition.dart';

appRouter() => nyRoutes((router) {

  // bottomToTop
  router.add(SettingsPage.path,
    transitionType: TransitionType.bottomToTop()
  );

  // fade
  router.add(HomePage.path,
    transitionType: TransitionType.fade()
  );

});

Transisi Halaman yang Tersedia

Transisi Dasar

  • TransitionType.fade() - Memfadekan halaman baru masuk sambil memfadekan halaman lama keluar
  • TransitionType.theme() - Menggunakan tema transisi halaman dari tema aplikasi

Transisi Geser Arah

  • TransitionType.rightToLeft() - Menggeser dari tepi kanan layar
  • TransitionType.leftToRight() - Menggeser dari tepi kiri layar
  • TransitionType.topToBottom() - Menggeser dari tepi atas layar
  • TransitionType.bottomToTop() - Menggeser dari tepi bawah layar

Transisi Geser dengan Fade

  • TransitionType.rightToLeftWithFade() - Menggeser dan memfadekan dari tepi kanan
  • TransitionType.leftToRightWithFade() - Menggeser dan memfadekan dari tepi kiri

Transisi Transformasi

  • TransitionType.scale(alignment: ...) - Menskalakan dari titik alignment yang ditentukan
  • TransitionType.rotate(alignment: ...) - Memutar di sekitar titik alignment yang ditentukan
  • TransitionType.size(alignment: ...) - Membesar dari titik alignment yang ditentukan

Transisi Joined (Memerlukan widget saat ini)

  • TransitionType.leftToRightJoined(childCurrent: ...) - Halaman saat ini keluar ke kanan sementara halaman baru masuk dari kiri
  • TransitionType.rightToLeftJoined(childCurrent: ...) - Halaman saat ini keluar ke kiri sementara halaman baru masuk dari kanan
  • TransitionType.topToBottomJoined(childCurrent: ...) - Halaman saat ini keluar ke bawah sementara halaman baru masuk dari atas
  • TransitionType.bottomToTopJoined(childCurrent: ...) - Halaman saat ini keluar ke atas sementara halaman baru masuk dari bawah

Transisi Pop (Memerlukan widget saat ini)

  • TransitionType.leftToRightPop(childCurrent: ...) - Halaman saat ini keluar ke kanan, halaman baru tetap di tempat
  • TransitionType.rightToLeftPop(childCurrent: ...) - Halaman saat ini keluar ke kiri, halaman baru tetap di tempat
  • TransitionType.topToBottomPop(childCurrent: ...) - Halaman saat ini keluar ke bawah, halaman baru tetap di tempat
  • TransitionType.bottomToTopPop(childCurrent: ...) - Halaman saat ini keluar ke atas, halaman baru tetap di tempat

Transisi Material Design Shared Axis

  • TransitionType.sharedAxisHorizontal() - Transisi geser dan fade horizontal
  • TransitionType.sharedAxisVertical() - Transisi geser dan fade vertikal
  • TransitionType.sharedAxisScale() - Transisi skala dan fade

Parameter Kustomisasi

Setiap transisi menerima parameter opsional berikut:

Parameter Deskripsi Default
curve Kurva animasi Kurva spesifik platform
duration Durasi animasi Durasi spesifik platform
reverseDuration Durasi animasi mundur Sama dengan duration
fullscreenDialog Apakah rute merupakan dialog fullscreen false
opaque Apakah rute bersifat opaque false
// Home page widget
class _HomePageState extends NyPage<HomePage> {

  _showProfile() {
    routeTo(ProfilePage.path,
      transitionType: TransitionType.bottomToTop()
    );
  }
...

Tipe Navigasi

Saat menavigasi, Anda dapat menentukan salah satu dari berikut ini jika Anda menggunakan helper routeTo.

Tipe Deskripsi
NavigationType.push Mendorong halaman baru ke tumpukan rute aplikasi Anda
NavigationType.pushReplace Mengganti rute saat ini, menghapus rute sebelumnya setelah rute baru selesai
NavigationType.popAndPushNamed Menghapus rute saat ini dari navigator dan mendorong rute bernama sebagai gantinya
NavigationType.pushAndRemoveUntil Mendorong dan menghapus rute sampai predikat bernilai true
NavigationType.pushAndForgetAll Mendorong ke halaman baru dan menghapus semua halaman lain pada tumpukan rute
// Home page widget
class _HomePageState extends NyPage<HomePage> {

  _showProfile() {
    routeTo(
      ProfilePage.path,
      navigationType: NavigationType.pushReplace
    );
  }
...

Navigasi kembali

Setelah Anda berada di halaman baru, Anda dapat menggunakan helper pop() untuk kembali ke halaman sebelumnya.

// SettingsPage Widget
class _SettingsPageState extends NyPage<SettingsPage> {

  _back() {
    pop();
    // or
    Navigator.pop(context);
  }
...

Jika Anda ingin mengembalikan nilai ke widget sebelumnya, berikan result seperti pada contoh di bawah ini.

// SettingsPage Widget
class _SettingsPageState extends NyPage<SettingsPage> {

  _back() {
    pop(result: {"status": "COMPLETE"});
  }

...

// Get the value from the previous widget using the `onPop` parameter
// HomePage Widget
class _HomePageState extends NyPage<HomePage> {

  _viewSettings() {
    routeTo(SettingsPage.path, onPop: (value) {
      print(value); // {"status": "COMPLETE"}
    });
  }
...

Navigasi Bersyarat

Gunakan routeIf() untuk menavigasi hanya ketika suatu kondisi terpenuhi:

// Only navigate if the user is logged in
routeIf(isLoggedIn, DashboardPage.path);

// With additional options
routeIf(
  hasPermission('view_reports'),
  ReportsPage.path,
  data: {'filters': defaultFilters},
  navigationType: NavigationType.push,
);

Jika kondisinya bernilai false, tidak ada navigasi yang terjadi.

Riwayat Rute

Di Nylo Website, Anda dapat mengakses informasi riwayat rute menggunakan helper di bawah ini.

// Get route history
Nylo.getRouteHistory(); // List<dynamic>

// Get the current route
Nylo.getCurrentRoute(); // Route<dynamic>?

// Get the previous route
Nylo.getPreviousRoute(); // Route<dynamic>?

// Get the current route name
Nylo.getCurrentRouteName(); // String?

// Get the previous route name
Nylo.getPreviousRouteName(); // String?

// Get the current route arguments
Nylo.getCurrentRouteArguments(); // dynamic

// Get the previous route arguments
Nylo.getPreviousRouteArguments(); // dynamic

Memperbarui Route Stack

Anda dapat memperbarui tumpukan navigasi secara programatis menggunakan NyNavigator.updateStack():

// Update the stack with a list of routes
NyNavigator.updateStack([
  HomePage.path,
  SettingsPage.path,
  ProfilePage.path,
], replace: true);

// Pass data to specific routes
NyNavigator.updateStack([
  HomePage.path,
  ProfilePage.path,
],
  replace: true,
  dataForRoute: {
    ProfilePage.path: {"userId": 42}
  }
);
Parameter Tipe Default Deskripsi
routes List<String> wajib Daftar path rute untuk dinavigasi
replace bool true Apakah mengganti tumpukan saat ini
dataForRoute Map<String, dynamic>? null Data yang dikirim ke rute tertentu

Ini berguna untuk:

  • Skenario deep linking
  • Memulihkan state navigasi
  • Membangun alur navigasi yang kompleks

Deep Linking

Deep linking memungkinkan pengguna menavigasi langsung ke konten tertentu dalam aplikasi Anda menggunakan URL. Ini berguna untuk:

  • Berbagi tautan langsung ke konten aplikasi tertentu
  • Kampanye pemasaran yang menargetkan fitur dalam aplikasi tertentu
  • Menangani notifikasi yang harus membuka layar aplikasi tertentu
  • Transisi web-ke-aplikasi yang mulus

Setup

Sebelum mengimplementasikan deep linking di aplikasi Anda, pastikan proyek Anda dikonfigurasi dengan benar:

1. Konfigurasi Platform

iOS: Konfigurasikan universal links di proyek Xcode Anda

Android: Atur app links di AndroidManifest.xml Anda

2. Definisikan Rute Anda

Semua rute yang harus dapat diakses melalui deep links harus didaftarkan di konfigurasi router Anda:

// File: /lib/routes/router.dart
appRouter() => nyRoutes((router) {
  // Basic routes
  router.add(HomePage.path).initialRoute();
  router.add(ProfilePage.path);
  router.add(SettingsPage.path);

  // Route with parameters
  router.add(HotelBookingPage.path);
});

Menggunakan Deep Links

Setelah dikonfigurasi, aplikasi Anda dapat menangani URL yang masuk dalam berbagai format:

Deep Links Dasar

Navigasi sederhana ke halaman tertentu:

https://yourdomain.com/profile       // Opens the profile page
https://yourdomain.com/settings      // Opens the settings page

Untuk memicu navigasi ini secara programatis di dalam aplikasi Anda:

routeTo(ProfilePage.path);
routeTo(SettingsPage.path);

Path Parameters

Untuk rute yang memerlukan data dinamis sebagai bagian dari path:

Definisi Rute

class HotelBookingPage extends NyStatefulWidget {
  // Define a route with a parameter placeholder {id}
  static RouteView path = ("/hotel/{id}/booking", (_) => HotelBookingPage());

  HotelBookingPage({super.key}) : super(child: () => _HotelBookingPageState());
}

class _HotelBookingPageState extends NyPage<HotelBookingPage> {
  @override
  get init => () {
    // Access the path parameter
    final hotelId = queryParameters()["id"]; // Returns "87" for URL ../hotel/87/booking
    print("Loading hotel ID: $hotelId");

    // Use the ID to fetch hotel data or perform operations
  };

  // Rest of your page implementation
}

Format URL

https://yourdomain.com/hotel/87/booking

Navigasi Programatis

// Navigate with parameters
routeTo(HotelBookingPage.path.withParams({"id": "87"}), queryParameters: {
              "bookings": "active",
            });

Query Parameters

Untuk parameter opsional atau ketika dibutuhkan beberapa nilai dinamis:

Format URL

https://yourdomain.com/profile?user=20&tab=posts
https://yourdomain.com/hotel/87/booking?checkIn=2025-04-10&nights=3

Mengakses Query Parameters

class _ProfilePageState extends NyPage<ProfilePage> {
  @override
  get init => () {
    // Get all query parameters
    final params = queryParameters();

    // Access specific parameters
    final userId = params["user"];            // "20"
    final activeTab = params["tab"];          // "posts"

    // Alternative access method
    final params2 = widget.queryParameters();
    print(params2);                           // {"user": "20", "tab": "posts"}
  };
}

Navigasi Programatis dengan Query Parameters

// Navigate with query parameters
routeTo(ProfilePage.path.withQueryParams({"user": "20", "tab": "posts"}));

// Combine path and query parameters
routeTo(HotelBookingPage.path.withParams({"id": "87"}), queryParameters: {
              "checkIn": "2025-04-10",
              "nights": "3",
            });

Menangani Deep Links

Anda dapat menangani event deep link di RouteProvider Anda:

class RouteProvider implements NyProvider {
  @override
  setup(Nylo nylo) async {
    nylo.addRouter(appRouter());

    // Handle deep links
    nylo.onDeepLink(_onDeepLink);
    return nylo;
  }

  _onDeepLink(String route, Map<String, String>? data) {
    print("Deep link route: $route");
    print("Deep link data: $data");

    // Update the route stack for deep links
    if (route == ProfilePage.path) {
      NyNavigator.updateStack([
        HomePage.path,
        ProfilePage.path,
      ], replace: true, dataForRoute: {
        ProfilePage.path: data,
      });
    }
  }

  @override
  boot(Nylo nylo) async {
    nylo.initRoutes();
  }
}

Menguji Deep Links

Untuk pengembangan dan pengujian, Anda dapat mensimulasikan aktivasi deep link menggunakan ADB (Android) atau xcrun (iOS):

# Android
adb shell am start -a android.intent.action.VIEW -d "https://yourdomain.com/profile?user=20" com.yourcompany.yourapp

# iOS (Simulator)
xcrun simctl openurl booted "https://yourdomain.com/profile?user=20"

Tips Debugging

  • Cetak semua parameter di metode init Anda untuk memverifikasi parsing yang benar
  • Uji berbagai format URL untuk memastikan aplikasi Anda menanganinya dengan benar
  • Ingat bahwa query parameters selalu diterima sebagai string, konversikan ke tipe yang sesuai sesuai kebutuhan

Pola Umum

Konversi Tipe Parameter

Karena semua parameter URL dikirim sebagai string, Anda sering perlu mengonversinya:

// Converting string parameters to appropriate types
final hotelId = int.parse(queryParameters()["id"] ?? "0");
final isAvailable = (queryParameters()["available"] ?? "false") == "true";
final checkInDate = DateTime.parse(queryParameters()["checkIn"] ?? "");

Parameter Opsional

Menangani kasus di mana parameter mungkin tidak ada:

final userId = queryParameters()["user"];
if (userId != null) {
  // Load specific user profile
} else {
  // Load current user profile
}

// Or check hasQueryParameter
if (hasQueryParameter('status')) {
  // Do something with the status parameter
} else {
  // Handle absence of the parameter
}

Lanjutan

Memeriksa Apakah Rute Ada

Anda dapat memeriksa apakah rute terdaftar di router Anda:

if (Nylo.containsRoute("/profile")) {
  routeTo("/profile");
}

Metode NyRouter

Kelas NyRouter menyediakan beberapa metode yang berguna:

Metode Deskripsi
getRegisteredRouteNames() Mendapatkan semua nama rute terdaftar sebagai daftar
getRegisteredRoutes() Mendapatkan semua rute terdaftar sebagai map
containsRoutes(routes) Memeriksa apakah router berisi semua rute yang ditentukan
getInitialRouteName() Mendapatkan nama rute awal
getAuthRouteName() Mendapatkan nama rute terautentikasi
getUnknownRouteName() Mendapatkan nama rute tidak dikenal/404

Mendapatkan Argumen Rute

Anda dapat mendapatkan argumen rute menggunakan NyRouter.args<T>():

class _ProfilePageState extends NyPage<ProfilePage> {
  @override
  Widget build(BuildContext context) {
    // Get typed arguments
    final args = NyRouter.args<NyArgument>(context);
    final userData = args?.data;

    return Scaffold(...);
  }
}

NyArgument dan NyQueryParameters

Data yang dikirim antar rute dibungkus dalam kelas-kelas ini:

// NyArgument contains route data
NyArgument argument = NyArgument({'userId': 42});
print(argument.data); // {'userId': 42}

// NyQueryParameters contains URL query parameters
NyQueryParameters params = NyQueryParameters({'tab': 'posts'});
print(params.data); // {'tab': 'posts'}