1

I am a Java programmer porting a Java SE/Swing app to a web app. I've been experimenting with node.js and express.js for the client-facing app.

I would like to define functions at the node.js app level and have the methods and properties available to views in the node app. I'm primarily concerned about data modeling. I'd like to define the data models at the app level, and have the views have access to properties and methods of the models.

I have investigated the express.js and node.js docs, and it appears to me that includes ('require' s) can be done at the app level but that they do not propogate to the view level.

Am I missing something? Perhaps it's something fundamental about JavaScript or Node that I don't get...

Matt Morgan
  • 4,900
  • 4
  • 21
  • 30
  • It's worth noting that if you can expose a REST API in your Java app (either by converting it to something like Spring, etc), you can do all the rendering on the front-end with [AngularJS](http://angularjs.org/) (easier learning curve) or [Backbone](http://backbonejs.org/) (more flexible) and avoid rewriting all your stuff in Node all together. – Michael Tang Dec 10 '13 at 21:14

1 Answers1

1

Note that expressjs is not really a MVC framework, and thus, it's concept of "routes", "app", and "views" are pretty loose and designed to be unopinionated and changed easily.

That said, an expressjs view is usually simply an HTML template (powered by EJS or Handlebars) provided by the router/controller and given a Javascript object to fill itself with. Many Javascript templating engines describe themselves as "logic-less templates". Because of this, there is a lack of functions/classes (note that Node/Javascript does not even really have a concept of classes). A suggestion might be to add a level of indirection in which you have a script that takes your model and packs it into some standard object format that all your templates know about.

Something also to note:

A require call in Node might be most akin to referencing a static Java class. (If I can find the reference I'm thinking of, I'll add it, but basically Node loads each script once and then returns the loaded copy for each subsequent require call. EDIT: here it is, node.Module source code)

EDIT: Some example for a mapping script

Note that there aren't very strong patterns in Node so far, so people seem to be doing what makes sense to them. This example is by no means the "standard" Node practice.

model-view.js

module.exports.map = function(birthyear) {
    return {
        "birthYear": birthYear,
        "age": getAge(birthYear)
    }
}

//some function on the "view"
function getAge(birthYear) {
    return (new Date()).getFullYear() - birthYear;
}

app.js

var transform = require('./model-transform');
app.get('/age/:user', function(req, res) {
    db.doSomeDatabaseRequestToGetTheUsersBirthYear(req.params.user, function(birthYear) {
        res.render('index', transform.map(birthYear));
    });
});

Template (I like mustache-based templates, but you can use whatever)

<html>
<body>
    You were born in {{ birthYear }}<br>
    You are probably {{ age }} years old.
</body>
</html>
Michael Tang
  • 4,686
  • 5
  • 25
  • 24
  • Michael, thanks for your input. Would you mind elaborating on 'add a level of indirection in which you have a script that takes your model and packs it into some standard object format that all your templates know about'? That, to me, is the missing piece. – Matt Morgan Dec 10 '13 at 00:55
  • I would imagine it's just a script (maybe `model-transform.js`?) that you have an exported function in that takes your data as parameters, then simply moves them around where you need them and spits them out as a formatted object. Then you could do something like `var transform = require('./model-transform'); ... res.render('index', transform.someFunction(your data));`. This might be synonymous to a mapping class in Java or such. – Michael Tang Dec 10 '13 at 20:58
  • Michael, inside the view, how do I reference the function or value passed in via the second parameter in res.render? EG, if I have event handler scripts called by the view that need access to objects referenced in the res.render call, can I manipulate them, and how? Thanks! – Matt Morgan Dec 11 '13 at 01:27
  • I'm not entirely sure what you're asking here. The "view" (read: template) is a logicless construction that doesn't support functions. You could either modify the data before it hits the view (before `res.render()`) or on client-side Javascript. Java/C++ ideas of MVC programming (and even classes/objects/methods) don't really translate well into Javascript. The basic structure of an express app is usually: Get a request (`app.get()`) -> handle request (get data to/from database) -> Render to client (as HTML or JSON). – Michael Tang Dec 11 '13 at 02:06
  • Some more research: Handlebars supports [block helpers](http://handlebarsjs.com/block_helpers.html), which let you define some function you can perform on data in your template. Express 3/EJS lets you define [arbitrary functions](http://stackoverflow.com/a/16098300/1500501) or [filters](http://stackoverflow.com/a/13224212/1500501) that are available within your template. – Michael Tang Dec 11 '13 at 02:10
  • It looks to me like these techniques will allow add text to the view, but not objects or scripts. – Matt Morgan Dec 11 '13 at 21:39
  • ...rather, not to send objects or scripts to the client. I'm trying to **require** scripts in my app that define data models and provide utility functions for the views, rather than have to put ` – Matt Morgan Dec 11 '13 at 21:51
  • OH! You may be able to simply want to just `app.use` the `static` middleware (http://expressjs.com/api.html#app.use, scroll down just a tad). This way, you can just serve client-side scripts as static files. At least in my experience with JavaScript web dev, the server's "views" only output JSON that the static client-facing front-end application code takes via ajax/xhr requests. It sounds like your Node server will just be a simple layer that maybe gets stuff to and from a database and most of your Swing app will be ported to client code. – Michael Tang Dec 15 '13 at 23:23
  • If that's the case, I'd highly recommend looking at Google's [AngularJS](http://angularjs.org/), as it's "get started and productive" learning curve is very easy. Beware, though, that most JS I've seen has a very different mindset from Java, and you may be straining to find parallels that may not exist. – Michael Tang Dec 15 '13 at 23:25