Controllers



Introduction

Before starting, let's go over what a controller is for those new.

Here's a quick summary by tutorialspoint.com.

{primary} The Controller is responsible for controlling the application logic and acts as the coordinator between the View and the Model. The Controller receives an input from the users via the View, then processes the user's data with the help of Model and passes the results back to the View.


Controller

app/controllers/home_controller.dart

...
class HomeController extends Controller {

  HomeController.of(BuildContext context) {
    super.context = context;
  }

  onTapDocumentation() {
    launch("https://nylo.dev/docs");
  }

  onTapGithub() {
    launch("https://github.com/nylo-core/nylo");
  }

  ...
}


Material Button - onPressed()

common/pages/home_page.dart

MaterialButton(
  child: Text(
    "GitHub",
    style: Theme.of(context).textTheme.bodyText1,
  ),
  onPressed: widget.controller.onTapGithub,
),

If your Widget contains a controller like the home_page.dart file, you can call the controller like widget.controller.

In the example above, the controller is defined within the constructor for the StatefulPageWidget like the below example.

class MyHomePage extends StatefulPageWidget {
  final HomeController controller;
  final String title;

  MyHomePage({Key key, this.title, this.controller}) : super(key: key);

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


Adding the controller in your router.dart file.

router.addRoute(NyRoute(
  name: "/",
  view: (context) => HomePage(
     controller: HomeController.of(context)
  )
));

You should avoid overloading widgets with functional logic and move it to your controller. You can also consider taking advantage of a service/repository pattern if your project requires it.


Creating a controller

You can use the Metro CLI tool to create your controllers or do it manually. Here's an example.

metro make:controller profile_controller

This will create a new controller in your app/controllers directory.

Or if you are creating a new page, use the -c flag to generate a controller with the page.

metro make:page profile_page -c

Retrieving arguments from routes

When you navigate to a new page, sometimes you may want to pass in data to a new view. This might look something like the below example.

// User object
User user = new User();
user.firstName = 'Anthony';

// Pass data into the navigation
NyNav.to('/profile', data: user);

Next, when we navigate to that page we need a way to retrieve the user. We can do this by calling widget.controller.request.data(); within the widget. Here’s an example below

...
class _ProfilePageState extends State<ProfilePage> {
  @override
  void initState() {
    super.initState();

  print(widget.controller.request.data().toString());

  }

This should log ‘User instance’ in the console and you’ll be able to use that object in your current view.

The data parameter accepts dynamic types so you can cast the object after it’s returned.


Api Service

If you need to make an API request from within your widget, you can call the widget.controller.apiService variable to access your ApiService from your widget.

This makes it easy to quickly make an API request from anywhere in as long as your widget has a controller defined.