.\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . .TH "COMPOUND\-CONTROLLER" "3" "November 2013" "1602 Software" "CompoundJS" . .SH "NAME" \fBcompound\-controller\fR \- controllers API . .SH "DESCRIPTION" Controller is a module that receives http request and handles response\. Controller consists of a set of actions\. Each action is called by the request of a particular route\. . .SH "SYNOPSIS" Controller receives control from router, if more then one routes matched by request \- first route will be served, then second, third, etc\.\. . .P It means that one request could be handled by one or more controllers matched by router sequentially until one of controllers will produce output\. . .P When no controllers produces output, then control returned to next middleware after express\.router\. . .SH "FILES" Controllers automatically loaded from \fB\./app/controllers\fR directory\. . .P Compound have two kind of controllers: when file name ended with \fB_controller\fR this is \fBeval\fR controller, otherwise controller is \fBnoeval\fR\. . .SS "EVAL CONTROLLERS" The purpose of eval controller \- provide convenient interface with less code and more expression\. But it have price: harder debugging and lack of usual features such as inheritance, meta\-programming and using relative \fBrequire\fR\. . .P By default compound generators create eval controllers, but this behavior will be changed in future because eval is evil\. See \fIUSING EVAL CONTROLLERS\fR section for specific usage details\. . .P Example of eval controller: \fBapp/controllers/car_controller\.js\fR: . .IP "" 4 . .nf load(\'essentials\'); // load parent controller before(function think() { // think for 1 second before acceperate setTimeout(function() { next(); }); }, {only: \'accelerate\'}); action(\'accelerate\', function() { send(++this\.speed); }); action(\'brake\', function() { send(\-\-this\.speed); }); . .fi . .IP "" 0 . .SS "NOEVAL CONTROLLERS" The opposite way to do the same things as in eval controller: more verbose, a little bit harder to read, but easier in debug\. Works as usual class: allows inheritance, meta\-programming, using require and all regular features\. . .P Example of noeval controller: \fBapp/controllers/car\.js\fR: . .IP "" 4 . .nf module\.exports = CarController; // load parent controller var Essentials = require(\'\./essentials\'); function CarController(init) { // call parent constructor Essentials\.call(this, init); init\.before(function think(c) { // think for 1 second before accelerate setTimeout(function() { c\.next(); }); }, {only: \'accelerate\'}); } // setup inheritance require(\'util\')\.inherits(CarController, Essentials); CarController\.prototype\.accelerate = function(c) { c\.send(++this\.speed); }; CarController\.prototype\.brake = function(c) { c\.send(++this\.speed); }; . .fi . .IP "" 0 . .P See \fIUSING NOEVAL CONTROLLERS\fR section for specific usage details\. . .SS "COMMON PARTS AND THE DIFFERENCE" Main difference between eval and noeval controllers: using controller context\. In case of eval it is possible just call controller context members as global variables: next, req, res, send, render and other features\. In noeval controller each action and hook accepts context object as first argument, all context features available on this object\. . .SS "USING EVAL CONTROLLERS" To define action call `action(name, fn) method\. This method accepts 1 or 2 arguments\. First argument (String name) is optional when named fn passed as action handler\. . .P To define hook just call \fBbefore\fR or \fBafter\fR methods\. . .SS "USING NOEVAL CONTROLLERS" Noeval controller file should export constructor, actions are prototype methods of that constructor\. Controller constructor accepts \fBinit\fR object which allows to configure controller on creation\. . .P To define hook call \fBbefore\fR or \fBafter\fR on \fBinit\fR object passed to constructor\. . .SH "MEMBERS" Controller context has the following set of members: . .TP \fBreq\fR Request object (instance of http\.IncomingMessage) . .TP \fBres\fR Response object (instance of http\.ServerResponse) . .TP \fBbody\fR Request body (null in case of GET) . .SH "OUTPUT METHODS" \fBNOTE:\fR Each action should invoke exactly one output method (render, send)\. This is the only requirement imposed by the asynchronous nature of Node\.js\. If you don\'t call an output method, the client will infinitely wait for a server response\. . .SS "render([view[, params]])" Render view and send result to client\. . .P The \fBrender\fR method accepts 0, 1 or 2 arguments\. When called without any arguments, it just renders the view associated with current action\. For example, this will render \fBapp/views/posts/index\.ejs\fR\. . .P Fragment of \fBapp/controllers/posts\.js\fR: . .IP "" 4 . .nf PostsController\.prototype\.index = function index(c) { c\.render(); }); . .fi . .IP "" 0 . .P To pass some data to the view, there are two ways to do it\. The first is to simply pass a hash containing the data: . .P Fragment of \fBapp/controllers/posts\.js\fR: . .IP "" 4 . .nf PostsController\.prototype\.index = function index(c) { this\.data = []; c\.render({title: \'Posts index\'}); }); . .fi . .IP "" 0 . .P Example above will render \'posts/index\' view passing \fBtitle\fR and \fBdata\fR to it\. . .P To render another view, just put its name as the first argument: . .P Fragment of \fBapp/controllers/posts\.js\fR: . .IP "" 4 . .nf PostsController\.prototype\.update = function update(c) { this\.title = \'Edit post\'; c\.render(\'edit\'); }; . .fi . .IP "" 0 . .SS "renderView(view[, callback])" Render view and return result to callback(err, html) or send to client when callback is missing\. This method does not accept params and works with \fBviewContext\fR member of controller\. Run \fBprepareViewContext\fR to create that member\. . .SS "send(smth)" Send text, status code or json object to client . .P The \fBsend\fR function is useful for debugging and one\-page apps where you don\'t want to render a heavy template and just want to send text or JSON data\. . .P This function can be called with a status code number: . .IP "" 4 . .nf Controller\.prototype\.destroy = function destroy(c) { // client will receive statusCode = 403 Forbidden c\.send(403); }); . .fi . .IP "" 0 . .P or with a string: . .IP "" 4 . .nf Controller\.prototype\.sayHello = function sayHello(c) { // client will receive \'Hello!\' c\.send(\'Hello!\'); }); . .fi . .IP "" 0 . .P or with an object: . .IP "" 4 . .nf Controller\.prototype\.action = function action(c) { // client will receive \'{"hello":"world"}\' c\.send({ hello: \'world\' }); }); . .fi . .IP "" 0 . .SS "redirect(location)" Redirect client to specific location . .P This function just sets the status code and \fBLocation\fR header, so the client will be redirected to another location\. . .IP "" 4 . .nf redirect(\'/\'); // root redirection redirect(\'http://example\.com\'); // redirect to another host . .fi . .IP "" 0 . .SS "header" Send header to client . .SS "flash(type, message)" Display flash message . .P The \fBflash\fR function stores a message in the session to be displayed later\. Here are a few examples: . .P Fragment of \fBapp/controllers/posts\.js\fR: . .IP "" 4 . .nf PostsController\.prototype\.create = function create(c) { c\.Post\.create(req\.body, function (err) { if (err) { c\.flash(\'error\', \'Error while post creation\'); c\.render(\'new\', {post: req\.body}); } else { c\.flash(\'info\', \'Post has been successfully created\'); c\.redirect(c\.pathTo\.posts); } }); }); . .fi . .IP "" 0 . .P This \fBcreate\fR action sends a flash info on success and a flash error on fail\. . .SH "FLOW CONTROL METHODS" To provide the ability of DRY\-ing controller code and reusing common code parts, CompoundJS provides a few additional tools: method chaining and external controllers loading\. . .SS "before([name, ]hook[, params])" Invoke \fBhook\fR before any action\. Name param is optional when hook is named function\. Examples of params object: . .IP "" 4 . .nf { only: [\'actionName\', \'actionName2\'] } { except: \'anotherActionName\' } . .fi . .IP "" 0 . .P First configuration will run hook only for \fBactionName\fR and \fBactionName2\fR actions\. Second configuration will run hook before each action except \fBanotherActionName\fR\. . .P To chain methods, you can use the \fBbefore\fR and \fBafter\fR methods\. . .P Fragment of \fBapp/controllers/checkout\.js\fR . .IP "" 4 . .nf function CheckoutController(init) { init\.before(userRequired, { only: \'order\' }); init\.before(prepareBasket, { except: \'order\' }); init\.before(loadProducts, { only: [\'products\', \'featuredProducts\'] }); } CheckoutController\.prototype\.products = function(c) { \.\.\. }; CheckoutController\.prototype\.featuredProducts = function(c) { \.\.\. }; CheckoutController\.prototype\.order = function(c) { \.\.\. }; CheckoutController\.prototype\.basket = function(c) { \.\.\. }; function userRequired(c) { c\.next() } function prepareBasket(c) { c\.next() } function loadProducts(c) { c\.next() } . .fi . .IP "" 0 . .P In this example, \fBuserRequired\fR will be called only for the \fBorder\fR action, \fBprepareBasket\fR will be called for all actions except \fBorder\fR, and \fBloadProducts\fR will be called only for the \fBproducts\fR and \fBfeaturedProducts\fRmethods\. . .P Note, that the before\-functions should call the global \fBnext\fR method that will pass control to the next function in the chain\. . .SS "after([name, ]hook[, params])" Invoke \fBhook\fR after any action\. Name param is optional when hook is named function\. Params object is the same as for before hook\. . .SS "skipBefore(name, params)" Skip before hook by it\'s name\. Params object allows to specify skip/only actions\. . .SS "skipAfter(name, params)" Skip after hook by it\'s name\. Params object allows to specify skip/only actions\. . .SS "next(err)" Go to next hook/action in chain\. When error param passed to next rest of chain skipped and error passed to error handling middleware\. . .SS "EVAL\-ONLY METHODS" Eval have a bunch of shims to allow code sharing between controllers (noeval doesn\'t need it, because it could use require and inheritance)\. . .TP \fBload\fR Load another controller to use its methods\. . .TP \fBuse\fR Get method defined in another controller, loaded using \fBload\fR\. . .TP \fBpublish\fR Allow method to be used in other controller\. . .IP Some methods, like \fBuserRequired\fR for example, can be used in different controllers\. To allow cross\-controller code sharing, CompoundJS provides a few methods: \fBload\fR, \fBuse\fR and \fBpublish\fR\. . .IP You can define \fBrequireUser\fR in \fBapplication_controller\.js\fR and call \fBpublish\fR to make it accessible to all other controllers that inherit from this controller: . .IP Fragment of \fBapp/controllers/application_controller\.js\fR: . .IP "" 4 . .nf publish(\'requireUser\', requireUser); function requireUser () { // \.\.\. } . .fi . .IP "" 0 . .IP Fragment of \fBapp/controllers/products_controller\.js\fR: . .IP "" 4 . .nf load(\'application\'); // note that _controller siffix omitted before(use(\'userRequired\'), { only: \'products\' }); . .fi . .IP "" 0 . .SS "COMMON EXECUTION CONTEXT" There is one extra feature in flow control: All functions are invoked in the same context, so you can pass data between the functions using the \fBthis\fR object: . .IP "" 4 . .nf function loadProducts () { Product\.find(function (err, prds) { this\.products = prds; next(); }\.bind(this)); } action(\'products\', function () { assert\.ok(this\.products, \'Products available here\'); render(); // also products will available in view }); . .fi . .IP "" 0 . .SH "EXTENDING" To extend controller context use \fBcompound\.controllerExtensions\fR object\. Methods of that object will be mixed to each controller context\. . .P For example, add method on initialization: . .IP "" 4 . .nf compound\.controllerExtensions\.socketSend = function(arg) { socketIO\.send(arg); }; . .fi . .IP "" 0 . .P Then it will be possible to call \fBsocket(\'hello\')\fR in eval controller, and \fBc\.socket(\'hello\')\fR in noeval controller\. . .SH "CONTRIBUTION" Compound uses npm package kontroller \fIhttp://npmjs\.org/package/kontroller\fR to handle controllers\. Any patches, feature requests or bug reports are welcome to its github repository: 1602/kontroller \fIhttps://github\.com/1602/kontroller\fR\. . .SH "SEE ALSO" compound\-views(3) compound\-helpers(3)