I'm trying out node and some frameworks for node atm, specifically locomotive. However, i seem to be stuck on routing using locomotive. A couple questions i can't find the answer to, so here goes:
why does the locomotive out-of-box install use index.html.ejs as a
filename? Why not just index.ejs? What's the benefit?
i'm trying to add a route to a view: searchName.html.ejs which i
added in the views folder. To achieve this i made a toolController
like this:
var locomotive = require('locomotive').Controller,
toolController = new Controller();
toolController.searchName = function() {
this.render();
}
module.exports = toolController;
I also added a route in routes.js like so:
this.match('searchName', 'tool#searchName');
However, that doesn't work (and yet it's what the documentation says ought to work). The result is a 404 error. So how do i make that route work?
Suppose i want to make a route to eg, anExample.html? How do i go
about that? I notice that in the out-of-the-box app from
locomotive, you cannot enter localhost:3000/index.html . Nor even
localhost:3000/index This seems highly impractical to me, as there
are plenty of users who'll add the specific page they want to go to.
So how can i make that work?
PS: I went through all questions regarding this on stackoverflow and searched the web, but i still can't figure this out.enter code here
The benefit is that this naming scheme allows you to specify several different formats for a single route. So you could have search_name.html.ejs and search_name.xml.ejs, then respond with either view depending on what your client is expecting.
There are a couple issues with the example code you posted. You should be seeing a more descriptive error than a 404, so I'm not sure what's happening there, but here are the fixes to your code that work in my environment.
In the controller:
//tool_controller.js
var locomotive = require('locomotive');
var toolController = new locomotive.Controller();
toolController.searchName = function() {
this.render();
};
module.exports = toolController;
In routes.js:
//routes.js
module.exports = function routes()
{
this.match('searchName', 'tool#searchName');
}
Then, you'll need to change the view to this: views/tool/search_name.html.ejs. It's not clear from the documentation, but locomotive automatically lowercases and underscores actions that are camel-cased, like searchName.
Now start the app and browse to http://localhost:3000/searchName
If you just want to serve a static html file, the easiest way is to just drop it in the public folder. This folder is specifically for serving up static content like client-side js, css, etc. And it works just fine for serving static HTML as well.
Related
I'm new to node, blah blah
I'm looking through some code I found, and encountered the lines
var app = express();
var glob = require('glob');
var controllers = glob.sync(config.root + '/app/controllers/*.js');
controllers.forEach(function (controller) {
require(controller)(app);
});
I understand that this goes and gets all the filenames of every file in /app/controllers/ that ends with .js, and sticks them in an array, then iterates over each one and calls a require on it. Makes sense, and looks like a nice way of not requiring each one individually. My question is what's that last (app) for? I tried looking at node documentation, but there is no require()() function. editing out the (app) leaves the code working fine with no errors, but doesn't load the controllers. If I had to take a guess, is it 'multiplying' the app by the found controller? Why would app.require(controller) not be a suitable option?
Thanks in advance
require is a part of node and is how modules are loaded. When you edit out the (app), it is probably still loading the controllers but because you haven't passed the app object over to each controller, they fail silently or return a controller object that doesn't work.
So something in the controller (probably a route being created or other similar stuff) needs to know about the app object and it has to be passed into the controller because app isn't in the global scope. You may want to review the node docs for module and globals as those will probably clear up WAY more than just this one question.
In my estimation we will have:
/* some-controller-file.js */
module.exports = function (app) {
/* do things with `app` */
}
So this allows you to use the created app inside of the controllers probably so you can attach routes.
I try to figure out how to set active links in a navbar or sitebar for an async ufront application.
On the server I can load and parse it dynamically inside the main (top level) controller via an api call like:
#inject public function init(context:HttpContext) {
ufTrace("HomeController::init");
var navStr:String = "";
//getNavbar loads the navbar html snippet and parses the code to set 'active' some tags in relation to the request uri
var navbarSurprise = siteApi.getNavbar(context.request.uri);
navbarSurprise.handle(function (outcome) {
switch (outcome) {
case Success(navbarStr): navStr = navbarStr;
case Failure(err): navStr = "<h1>Could not load navigation: $err</h1>";
}
} );
ViewResult.globalValues["navBar"] = navStr;
}
but that doesn't work on the client for pushstate urls. (navStr would always be empty)
The ViewResult.hx (line:126) doc states:
Helpers (dynamic functions) can be included in your ViewResult also.
Could this be a place to handle that?
But unfortunately I couldn't find any help/examples how to add helper functions to a ViewResult.
I was also thinking about doing it in a custom ViewEngine. But that seems a bit like overcomplicating things.
Any thoughts about that would be appreciated.
Seems your are looking to render the navbar on the server when processing the request.
I did something like that some time ago by using sipple (another templating engine) but you can also use other engine (i think) like haxe template or erazor etc.
This issue sums up how i processed different partials using stipple
Hope it helps.
I'm sure this question has been asked many a time before but I am having zero luck finding my 'question'.
I'm trying to figure out what the best solution is to loading a js file dynamically depending on the page/url. Should I handle this in controllers?
Am I right in assuming I should be using something like Browserify or requireJS? I do not understand how they are used in this manner, though...
I'm using Expressjs
I had something like this...
assets = {
js: {
validation: 'path/to/file'
}
}
route/controller
res.render('example', {
scripts: [assets.js.validation]
}
)
view (using a view engine helper)
just an example of logic
each script in scripts
<script src="{[script}}">
This works but I'm wondering what's best practice.
I'm designing an app with node.js and Express, and I was wondering if it was possible to move certain routing logic out of the app.js file. For exapmle, my app.js currently contains:
app.get('/groups',routes.groups);
app.get('/',routes.index);
Is there a way to move this logic out of the app.js file, and only have something like:
app.get('/:url',routes.get);
app.post('/:url",routes.post);
such that all GET requests would be processed by routes.get and all POST requests processed with routes.post?
You could pass a regular expression as the route definition:
app.get(/.+/, someFunction);
This would match anything. However, if you simply want to move your route definitions outside of your main app.js file, it is much clearer to do something like this:
app.js
var app = require('express').createServer();
...
require('routes').addRoutes(app);
routes.js
exports.addRoutes = function(app) {
app.get('/groups', function(req, res) {
...
});
};
This way, you're still using Express' built-in routing, rather than re-rolling your own (as you'd have to do in your example).
FULL DISCLOSURE: I am the developer of the node module mentioned below.
There is a node module that does kind of what you're asking for (and will, eventually, do more). It offers automatic routing based on convention over configuration for express. The module name is honey-express, but is currently in alpha development and not yet available on NPM (but you can get it from the source at https://github.com/jaylach/honey-express.
A short example of how it works: (Please note that this coffeescript)
# Inside your testController.coffee file. Should live inside /app/controllers
honey = require 'honey-express'
TestController = new honey.Controller
index: ->
# #view() is a helper method to automatically render the view for the action you're executing.
# As long as a view (with an extension that matches your setup view engine) lives at /app/views/controller/actionName (without method, so index and not getIndex), it will be rendered.
#view()
postTest: (data) ->
# Do something with data
Now, inside your app.js file you just have to setup some simple configuration:
# in your app.configure callback...
honey.config 'app root', __dirname + '/app'
app.use honey.router()
Now anytime a request comes in, honey will automatically look for a controller with the specified route, and then look for a matching action.. for example -
/test will automatically route to the index/getIndex() method of
testController
/ will automatically route to the index/getIndex() method of the homeController (the default controller is home), if it exists
/test/test will automatically route to the postTest() method of testController if the http method is POST.
As I mentioned, the module is currently in it's alpha state but the automatic routing works wonderfully and has been tested on two different projects now :) But since it's in alpha development, the documentation is missing. Should you decide to go this route, you can look at the sample I have up on the github, look through the code, or reach out to me and I'd be happy to help :)
EDIT: I should also note that honey-express does require the latest (BETA) version of express as it uses features that are not present in 2.x of express.
I'm thoroughly confused on how to use an npm module in Meteor client code.
I understand modules like fs would only work server-side, but in this case I'd like to use a simple text module like this for displaying pretty dates:
https://github.com/ecto/node-timeago
I've tried installing the module under /public/node_modules,
and it works great on the server-side following these instructions from SO: (
How do we or can we use node modules via npm with Meteor?)
Meteor.startup(function () {
var require = __meteor_bootstrap__.require
var timeago = require('timeago')
console.log(timeago(new Date()))
...
However it doesn't work in the client-side code:
if (Meteor.is_client) {
var require = __meteor_bootstrap__.require
var timeago = require('timeago')
console.log(timeago(new Date()))
...
Uncaught ReferenceError: __meteor_bootstrap__ is not defined"
Server-side is sort of useless for me in this case, as I'm trying to render text on the client.
I don't believe you need to use the server side version. Use the npm stuff for server side only and btw, put it in your /public/ as well. Who knows maybe you can call it once it is in your /public/, try it. Or try this.
Use something like the jquery timeago.js
Put it in /client/ or something like /client/js
Create a /client/helpers.js or some such.
Use a handlebars helper.
Handlebars.registerHelper('date', function(date) {
if(date) {
dateObj = new Date(date);
return $.timeago(dateObj);
}
return 'a long long time ago in a galaxy far away';
});
Example of calling 'date' handlebars helper function from template.
{{ date created }}
Where date is the handebars helper and created is the date coming out of the meteor/mongo collection.
See the github Britto project. That is where I got this code snippet and used it in a chat room app I wrote. Works fine.
There are a couple of others floating out there. Go to madewith.meteor.com and peruse the source of some of the projects.