How to create absolute links in Node.js? - node.js

I'm using Node.js with Express, Connect, and Jade. I want to provide an absolute link to a route in my application, but I can't find how to do this. I must be missing something, because this seems like a simple task.
I can do this: /myroute
But what I want is this: http://localhost:3000/myroute
There must be a helper somewhere that does this, right?

I created my own helper for this, which doesn't feel like the greatest solution.
Helpers = {
toAbsolute: ( url, req ) ->
'http://' + req.headers.host + url
}
DynamicHelpers = {
req: ( req, res ) ->
req
}
exports.Helpers = Helpers
exports.DynamicHelpers = DynamicHelpers
I add the helpers in my app.coffee file:
helpers = require './helpers.js'
# Helpers
app.helpers helpers.Helpers
app.dynamicHelpers helpers.DynamicHelpers
In my [jade] view, this is what I do to get an absolute URL from a relative URL:
| link text

There's no 'helper', but you could write your own by injecting req.query variables into the jade local variables for the route.
Personally, I'd do it client-side using window.location.origin.

update: actually, this only seems to work if req is from a POST, not a GET. :(
update 2: ugh, it's not even consistent across browsers. and neither is tim's. To find the solution I ended up using, google "window.location.origin considered harmful".
req.headers.origin appears to return something like 'http://example.com:1234' when the browser hits 'http://example.com:1234/something'.
this seems to be the express equivalent to #timoxley's client-side solution. :)
It's only a little bit simpler than yours, but it removes the need for a literal 'http' (or https).

Related

Routing in locomotive using ejs

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.

ExpressJS Route Parameter with Slash

Im using ExpressJS. I want pass url as parameter.
app.get('/s/:url', function(req, res) {
console.log(req.params.url);
});
/s/sg.com //sg.com
/s/www.sg.com //www.sg.com
/s/http://sg.com //http://sg.com
/s/http://sg.com/folder //http://sg.com/folder
How to correct the route such that everything afterr /s/ will be considered as paramenter including slashes.
Thanks
Uh, if you want to stick a URL inside of another URL, you need to URLencode it. If you want to stick one in their raw and suffer the consequences, just use app.get('/s/*'... and then manually parse out the url with req.url.slice(3). But hear me know and believe me later, URL Encoding is the right way to do this via the encodeURIComponent that is built in to JavaScript and works in both the browser and node.js.

Get return value of `include` in jade template

What I basically try to accomplish is to re-use jade partials/templates when getting data through a socket connection. Non working example:
socket.on('company_created', function(company) {
var html = include _company;
$('#companies ul').append(html);
});
Normally I had to create a new li and set the content like so (which is working as expected):
$('#companies ul').append($('<li>').text(company.name));
This is okay for a simple list, but if I had complexer list and stuff, this could get messy pretty quick, plus I had to write plain HTML again, so I figured re-using my already existing jade templates with all their goodness would be awesome, but had not luck, yet.
Any clue?
PS: Please do not tell my to use Ember, Backbone, Derby, Meteor, Angular or whatsoever.
Thanks in advance!
You can compile your jade sources to JS with jade.compile. Then include these sources in the client-side javascript, include jade's runtime.min.js, and refer to your jade templates as to normal JS functions in your client-side code.
For example,
server.js
app.get('/templates/:template.js', function (req, res) {
var template = req.params.template;
response.end([
"window.templates = window.templates || {};",
"window.templates[\"" + template + "\"] = " + jade.compile(template + ".jade", { client: true; });
].join("\r\n"));
});
client.js
$(function() { $("#placeholder").html(window.templates["content"]({user: "Daniel" })); });
content.jade
h1: Hello #{user}!
index.jade
!!!
html
head
script(src='/lib/jquery/jquery.js')
script(src='/lib/jade/runtime.min.js')
script(src='/templates/content.js')
script(src='/scripts/client.js')
body
#placeholder
Note that the code above might be syntactically incorrect and is provided solely to illustrate the idea.
we have a build step that compiles them to functions sort of like penartur mentioned. I dont use extend or include (which dont work on the client anyway ATM), but personally I find we have absolutely no need for that on the client at all since the DOM provides all the separation we need.

Several individual static directories with different paths using Express

I would like to be able to get Express to treat several directories (not just one) as "static" -- that is, if the file is there, then serve it.
Connect's static() module seems to be geared up for people who want to make files in a specific directory available in the server's root. However, that's not what I want. What I am after, is end up with something like this:
GET /modules/MODULE1 -> Return files in modules/MODULE1/public
GET /modules/MODULE2 -> Return files in modules/MODULE2/public
GET /modules/MODULE3 -> Return files in modules/MODULE3/public
I am looking at the source of static, which in turns uses send, which in turns defines SendStream, which takes the file path straight from the request (which is not what I want).
Are there easy ways to do this?
Merc.
what's wrong with
app.use('/modules/MODULE1', express.static('modules/MODULE1/public'))
for each module?
The answer is here:
https://groups.google.com/forum/?fromgroups=#!topic/express-js/kK9muR0mjR4
Basically:
var st = express.static(
__dirname + app.set('path.static'),
{ maxAge : app.set('static.expiry') }
);
app.get(/^\/static\/(v.+?\/)?(.+$)/, function (req, res, next) {
req.url = req.params[1];
st(req, res, next);
});
Basically, since Static consider req.url, it's a matter of hacking it so that it "looks right" when/if the path matches.
I asked TJ if he would add it as an option, he (rightly) answered:
this isn't something send() should do, you can already do this easily with connect/express with several static() middleware, you would just have to do the same but more manual with send()
https://github.com/visionmedia/send/issues/10#issuecomment-8225096

express-resource custom mapping

I can't find any decent documentation on this that contains any depth when requiring with app.resource.
The only information that I can find is creating the variable within the current file. Here
The current code that I have is below:
var favs = app.resource('favs', require('./modules/favs'));
favs.map('get', '/user', favs.buses);
However it comes back saying that it is undefined?
In the module favs I have.
exports.buses = function (req, res) {
res.render('favs/buses', {
title: 'Bus Stops'
});
});
You have a syntax error in favs.js: The last right bracket ) is redundant.
Apart from that, you seem to conflate the actual module with the resource object you get back from app.resource. You want to pass a reference to the request handler you want to invoke when a visitor hits the path (in your case, /favs/user). So what you want is something like:
var favs = require('./modules/favs'),
favsResource = app.resource('favs', favs);
favsResource.map('get', '/user', favs.buses);
If you feel a little lost dealing with express-resource, I encourage you to begin with plain express, and only start using express-resource when you are more familiar with how express works. TJ's helper modules have a tendency to be lacking in documentation, and you should use them only if you feel comfortable reading the code, IMO.

Resources