Controllers
Introduction
In EJS, a controller is a class responsible for providing action methods to execute specific functionality within a module.
Acting as an interface to a module, controllers provide predefined functionality which may be called from the application.
Controller classes
A controller is a class that resides in a module's Controller
namespace and has its name suffixed with Controller. Each controller class may optionally include a constructor which will be passed the active module instance and the application's file loader.
In many cases, a module only needs a single controller. However, for larger modules, it is a good idea to group related functionality into multiple controllers.
class MyFirstController
{
constructor(module, loader) {}
}
Action methods
An action method is a method on a controller class with its name suffixed with Action. The application will call these methods to interact with modules from the outside. This ensures that a module can properly dictate how it should be used while preventing coupling to the application itself.
Action methods may optionally return a value. If the returned value is a component, it will be inserted into the active layout.
Asynchronous action methods
An asynchronous action method is a method that may not return immediately as it needs to wait for its processing to complete (e.g. waiting for a component to load). Instead of returning a value directly, asynchronous action methods return a Promise that will resolve to the return value.
Example: Loading resources just-in-time
class MyFirstController
{
constructor(module, loader) {
this.module = module;
this.loader = loader;
}
async indexAction() {
// Get the path to this module's Component namespace.
let pathToComponent = this.module.map().componentPath();
return this.loader.load(pathToComponents + '/IndexPage.vue');
}
}
Synchronous action methods
A synchronous action method is a method that does not contain any asynchronous processing, and optionally returns a value immediately.
Synchronous action methods are most useful for preloading related resources.
Example: Preloading resources
In this example, MyComponent
and its dependencies will be loaded recursively when MyFirstController
is loaded. When mySyncMethodAction
is called, it can return MyComponent immediately as it is already loaded.
Preloading resources should be used sparingly and primarily for optimization when necessary. Excessive preloading can cause performance issues resulting from network or memory limits.
const MyComponent = use('Module/MyModule/Components/MyComponent.vue');
class MyFirstController
{
mySyncMethodAction() {
console.log('Running my action method!');
return MyComponent;
}
}
Using an abstract controller
When designing your controllers, it's likely you'll want to share some common functionality across many or all of them.
EJS provides a simple abstract controller with some convenience methods:
ElentraJS/Controller/ControllerAbstract#respond(componentName)
Accepts the filename of a component, relative to the module'sComponent
namespace. Returns a Promise that will resolve to the component when it is loaded.
Example: Use an abstract controller via composition
const ControllerAbstract = use('ElentraJS/Controller/ControllerAbstract');
class MyFirstController {
constructor(module, loader) {
this.controller = new ControllerAbstract(module, loader);
}
async indexAction() {
return this.controller.respond('IndexPage.vue');
}
}
Example: Use an abstract controller via inheritance
const ControllerAbstract = use('ElentraJS/Controller/ControllerAbstract');
class MyFirstController extends ControllerAbstract {
// Tip: You may omit this constructor if the super call is its only statement.
constructor(module, loader) {
super(module, loader);
}
async indexAction() {
return this.respond('IndexPage.vue');
}
}
Last updated