How to properly render partial views, and load JavaScript files in AJAX using Express/Jade? How to properly render partial views, and load JavaScript files in AJAX using Express/Jade? ajax ajax

How to properly render partial views, and load JavaScript files in AJAX using Express/Jade?


Great question. I don't have a perfect option, but I'll offer a variant of your solution #3 that I like. Same idea as solution #3 but move the jade template for the _full file into your code, since it is boilerplate and javascript can generate it when needed for a full page. disclaimer: untested, but I humbly suggest:

app.use(function (req, res, next) {    var template = "extends layout.jade\n\nblock content\n    include ";      res.renderView = function (viewName, opts) {        if (req.xhr) {            var renderResult = jade.compile(template + viewName + ".jade\n", opts);            res.send(renderResult);        } else {            res.render(viewName, opts);        }        next();    }; });

And you can get more clever with this idea as your scenarios become more complicated, for example saving this template to a file with placeholders for file names.

Of course this is still not a perfect solution. You're implementing features that should really be handled by your template engine, same as your original objection to solution #3. If you end up writing more than a couple dozen of lines of code for this then try to find a way to fit the feature into Jade and send them a pull request. For example if the jade "extends" keyword took an argument that could disable extending the layout for xhr requests...

For your second problem, I'm not sure any template engine can help you. If you're using ajax navigation, you can't very well "unload" page_a.js when the navigation happens via some back end template magic. I think you have to use traditional javascript isolation techniques for this (client-side). To your specific concerns: Implement the page specific logic (and variables) in closures, for starter, and have sensible cooperation between them where necessary. Secondly, you don't need to worry too much about hooking up double event handlers. Assuming the main content gets cleared on ajax navigation and also those are the elements that had the event handlers get attached that will call get reset (of course) when the new ajax content is loaded into the DOM.


Not sure if it's really going to help you but I solved the same problem with Express and ejs template.

my folder:

  • app.js
  • views/header.ejs
  • views/page.ejs
  • views/footer.ejs

my app.js

app.get('/page', function(req, res) {    if (req.xhr) {        res.render('page',{ajax:1});    } else {        res.render('page',{ajax:0});    }});

my page.ejs

<% if (ajax == 0) { %> <% include header %> <% } %>content<% if (ajax == 0) { %> <% include footer %><% } %>

very simple but works perfect.


There are several ways to do what you asked, but all of them are bad architecturally. You may not notice that now, but it's will be worse and worse with time.

Sounds weird at this point, but you don't really want to transmit you JS, CSS via AJAX.

What you want is to be able to get the markup via AJAX and to do some Javascript after that. Also, you want to be flexible and rational while doing this. Scaleability is important as well.

The common way is:

  1. Preload all the js files could be used at the particular page and its AJAX requests handlers. Use browserify if your afraid of potential names conflicts or script sideeffects. Load them asynchronously (script async) to not make user wait.

  2. Develop an architecture that enables you to do, basically, this at the client: loadPageAjax('page_a').then(...).catch(...). The point is, since you have pre-downloaded all the JS modules, to run you AJAX-page related code at the caller of the request and not at the callee.

So, your Solution #4 is nearly good. Just use it to fetch the HTML, but not scripts.

This technique gets your goal done without building some obscure architecture, but using the single robust goal-limited way.

Will happy to answer any further questions and convince you not to do what you are going to.