How to display node.js locals in vash views (UPDATE) - javascript

What I am trying to do:
Using middleware function I want to store user data from session in to locals so I can use it later in my views without store those data in every method / controller.
Instead of (in every method / controller):
function(req, res){
data.user = req.session.user;
res.render('someView', data);
}
and in View (template):
<div>
#model.user.username
</div>
i want to define middleware like this:
if (req.session.user) {
var now = new Date().getTime();
var data = req.session.user;
var timeout = data.loggedIn + config.auth.timeout;
if (timeout < now) {
req.session.user = null;
reg.flash('errors', {
param: 'default',
msg: 'Your session is expired...'
});
return res.redirect('/login');
}
res.locals.user = sesData;
}
return next();
and in view display my data from res.locals. And there is my BIG questionmark... is it possible ?
I could find any information how to display data from res.locals in vash views.
Am i missing something, is my solution plausible ?
UPDATE
Finally i found solution. Displaying app.locals in VASH views is quite simple :-)
View:
<div>
#model._locals.user.username
</div>
would do what i need :-)
I hope someone will find it useful.

Related

Make old links backwards compatible in express

You have an application created in express and angular that allows the user to perform a search. The URL is built based upon the search that was just performed. So if you perform a search on “Will” the url looks like http://localhost.com:9000/search/query?q=Will Everything works fine but you forgot that the app previously performed searches without the /query?= and now all of your old links like http://localhost.com:9000/search/will or http://localhost.com:9000/search/roberto no longer work.
What would be the correct approach to get the old links working again?
Should you use JavaScript on the frontend to look for /query?= missing in the URL and add after the search path but before the queried text?
It'd be easier to do a redirect on the Express back-end.
Say your code for the /search/query path is initially like this :
app.get("/search/query", function (req, res) {
// Do your query validation and fetch your search result.
// Here, I just check if a query value was given or not for the q param.
// I recommend you use better ways to check for empty queries.
// (ex: lodash's `isEmpty()` function)
if (req.query.q) {
// Serve the page !
res.send("What you want to render if the search result finds something.");
}
else {
// Return an error !
res.status(404).send("Nothing was found with the criterias entered.");
}
});
This is probably similar to what you have. Now, here is the answer to your question, based on the initial implementation above :
app.get("/search/query", function (req, res, next) {
// Check if a query value was given AND if the value isn't equal to "query".
// The later condition is to prevent infinite loops.
if (req.query.q && req.query.q !== "query") {
// Redirect using the value assigned to the q query param.
res.redirect("/search/" + req.query.q);
}
else {
// Since there is no query parameter named `q` in the request,
// we can be sure that `query` reffers to a search term.
next();
}
});
app.param("srchterm", function (req, res, next, value) {
// Check, for example, if the value isn't empty.
if (value) {
// Do your query validation and fetch your search result HERE.
// Add those results in an array in the res.locals object.
// Those results can be used later.
res.locals.results = ["all", "your", "search", "results"];
}
next();
});
app.get("/search/:srchterm", function (req, res) {
console.log("another blah");
// We don't need to fetch the data here anymore, since it's handled by the param parser above!
// However, it's still necessary to check if the search gave back some results.
if (res.locals.results) {
// Serve the results !
res.send("A total of " + res.locals.results.length + " results were found for " + req.params['srchterm']);
}
else {
// Return an error !
res.status(404).send("Nothing was found with the criterias entered.");
}
});
So from now on, every query using /search/query?q=123 will redirect towards /search/123. It even lets you use query as the search term!
Just use a regex and redirect
app.use(function(req, res, next) {
var searchRegEx = /\/search/g;
var searchedTerm = req.originalUrl.replace(searchRegEx, '');
var queryPath = req.originalUrl.match(/\/query[?]q=/);
if(!queryPath) {
var regexSlash = /\//g;
res.redirect('query?q=' + searchedTerm.replace(regexSlash, ''));
}
else {
next();
}
});

How use next() properly in routes (node.js)

var s_bookingController = require('s/controllers);
app.get('/dashboard/:page/:param', s_bookingController.index)
app.get('/dashboard/show/:id', s_bookingController.show);
Controllers:
exports.index = function(req, res, next) {
var page = parseInt(req.param("id"));
data = {};
data.page = page;
data.nextPage = page + 1;
data.prevPage = page - 1;
MyModel.find().sort('brand').skip((page-1)*11).limit(11).exec(function(err, result) {
res.render('index', {
data: data,
booking: result,
});
});
};
And
exports.show = function(req, res, next) {
var id = req.param("id");
res.send(id);
};
I'm using this controllers, but there is something wrong with the code of the exports.index, because it's stuck in the code.
If I change the routes to:
app.get('/dashboard/:page', s_bookingController.index)
(Note that I'm take off the second parameter that I was passing)
the show will work, but if I use the second parameter, the show will not run, it will be stuck in the index page.
Why is this? I was wondering if I need use the next();.
Expanding my comment:
You should have the following order of the routes:
app.get('/dashboard/show/:id', s_bookingController.show);
app.get('/dashboard/:page/:param', s_bookingController.index);
Express routing requires that a more specific route should be placed above the more general one.
The /dashboard/show/:id is more specific in this case as /dashboard/:page/:param covers it, so that /dashboard/show is handled by it. When the route is handled next routes are not executed.

how to avoid 'this' issue in function used as express route callback

I am trying to write a module that creates generic handlers for express routes
e.g.
//create a new route handler with some config
//every routeHanlder method needs to be able to access this config
var handler = new routeHandler({config: "value"});
//handle a get route ("Example 1")
app.get('route', handler.read)
//handle a get route with params ("Example 2")
app.get('route.:id', function(req, res){
handler.read(req,res,{query: {_id: req.params.id}});
});
I am having trouble making "example 1" work...
app.get('route', handler.read)
...as I loose the value of 'this' inside handler.read
I understand why the value of 'this' is different, but I can't figure out how to make it work, or another way to get the desired results without using 'this'.
Here is a plunker link
To summarise I am trying to find a way to make my routeHandler objects (see plunker above, and code paste below) work when used as the callback of an express route (see "example 1" above).
var routeHandler = function(config){
if (!(this instanceof(routeHandler))) {
return new routeHandler(config);
}
config = config || {};
if(config.configData){
this.configData = config.configData;
}
};
routeHandler.prototype = {
read: function(req, res, options){
//The problem: accessing configData without using this
console.log("inside callback", this, this.configData);
options = options || {};
}
};
Edit: I would like the ability to create multiple instances of the route handler with different config data e.g.
var handlerOne = new RouteHandler("configDataOne");
var handlerTwo = new RouteHandler("configDataTwo");
app.get('/firstRoute', handlerOne.read);
app.get('/secondRoute', handlerTwo.read);
You can save routeHandler's configData in express object "app" like below:
app.set("routeHandlerConfigData", "identifier or whatever value you want to store");
then make your routeHandler a simple middleware
var routeHandler = function(req, res, next){
var configData = req.app.get("routeHandlerConfigData");
//Do whatever you want
};
I was inspired by a great comment form yerforkferchips who suggested adding my routerHandler functions inside the constructor like this
this.read = (function read(...) { ... }).bind(this);
Which lets me do exactly what I wanted in my question
app.get('route', handler.read);
BUT i realised that I could use closures in my prototype functions which would sort my 'this' problem and that I would also be able to take in configuration data without having to wrap handler.read in a separate callback function on app.get
RouteHandler.prototype = {
read: function(config){
return function(req, res){
//I have access to req, res and config
}
}
}
so now I can do this
app.get('route', handler.read("configData"));
instead of this
app.get('route', function(req, res){
hander.read(req, res, "configData");
});

How do I get a hold of a Strongloop loopback model?

This is maddening, how do I get a hold of a loopback model so I can programmatically work with it ? I have a Persisted model named "Notification". I can interact with it using the REST explorer. I want to be able to work with it within the server, i.e. Notification.find(...). I execute app.models() and can see it listed. I have done this:
var Notification = app.models.Notification;
and get a big fat "undefined". I have done this:
var Notification = loopback.Notification;
app.model(Notification);
var Notification = app.models.Notification;
and another big fat "undefined".
Please explain all I have to do to get a hold of a model I have defined using:
slc loopback:model
Thanks in advance
You can use ModelCtor.app.models.OtherModelName to access other models from you custom methods.
/** common/models/product.js **/
module.exports = function(Product) {
Product.createRandomName = function(cb) {
var Randomizer = Product.app.models.Randomizer;
Randomizer.createName(cb);
}
// this will not work as `Product.app` is not set yet
var Randomizer = Product.app.models.Randomizer;
}
/** common/models/randomizer.js **/
module.exports = function(Randomizer) {
Randomizer.createName = function(cb) {
process.nextTick(function() {
cb(null, 'random name');
});
};
}
/** server/model-config.js **/
{
"Product": {
"dataSource": "db"
},
"Randomizer": {
"dataSource": null
}
}
I know this post was here a long time ago. But since I got the same question recent days, here's what I figured out with the latest loopback api:
Loopback 2.19.0(the latest for 12th, July)
API, Get the Application object to which the Model is attached.: http://apidocs.strongloop.com/loopback/#model-getapp
You can get the application which your model was attached as following:
ModelX.js
module.exports = function(ModelX) {
//Example of disable the parent 'find' REST api, and creat a remote method called 'findA'
var isStatic = true;
ModelX.disableRemoteMethod('find', isStatic);
ModelX.findA = function (filter, cb) {
//Get the Application object which the model attached to, and we do what ever we want
ModelX.getApp(function(err, app){
if(err) throw err;
//App object returned in the callback
app.models.OtherModel.OtherMethod({}, function(){
if(err) throw err;
//Do whatever you what with the OtherModel.OtherMethod
//This give you the ability to access OtherModel within ModelX.
//...
});
});
}
//Expose the remote method with settings.
ModelX.remoteMethod(
'findA',
{
description: ["Remote method instaed of parent method from the PersistedModel",
"Can help you to impliment your own business logic"],
http:{path: '/finda', verb: 'get'},
accepts: {arg:'filter',
type:'object',
description: 'Filter defining fields, where, include, order, offset, and limit',
http:{source:'query'}},
returns: {type:'array', root:true}
}
);
};
Looks like I'm not doing well with the code block format here...
Also you should be careful about the timing when this 'getApp' get called, it matters because if you call this method very early when initializing the model, something like 'undefined' error will occur.

Partial update while supporting seo

Using NodeJs I'm trying to do something quite similar to Meteor: I want to send only the parts of a page that actually changed. My dilemma is that I know how to create such a framework to respond to link clicks and send partial updates but such a framework won't cater to direct browsing to a page other than the index (which is what is required for search engines and people without javascript to use your site).
I can also figure out how to make a framework to support entire page reloads, handlebars and a simple node server instance would take care of that. Hoeever, I can't figure out how to create a way that would allow me to write one method to tell the framework the partial updates for a page and let the framework figure out what else needs to be loaded.
A way I can think of would be to create the index page every time (for entire page loads) and apply partial updates to that but that can quickly become expensive if a subpage differs a lot from a very crowded index.
An example method would look something like this:
function images(id) {
if (id == null) {
// load all images from database
template.images = db.result();
template.content = template.loadblock('gallery');
}
else {
// retrieve single image
template.content = template.loadblock('single_image');
template.image = db.result();
}
}
On a partisl updste calling this method for domain.com/images would work just fine because it's clear what had changed.
For an entire page load this function would miss things like a header, footer ,navigation, etc.
In an answer I would look for an example where this has been done or some tips that Can point me in the right direction. I'm sorry for any typoes I wrote this post on an ipad. If you have any questions about my question just ask and I'll update as needed.
Update:
A possible example of a solution might be the following code. It's to give an idea, it probably won't actually run
// As a convention, don't pass around raw values if they aren't static but pass around functions such as
data.images = function () {
// run db query
// return an object with the images
}
// This constraint might be limited to the index() method
var routes = {
// This now allows us to do things like this:
index: function() {
var data;
// Initialise everything needed for the index
data.title = 'Index';
data.nav = { Index: '/', Images: '/images' };
data.content = 'Hello World';
},
categories: function() {
var data;
data.content = render('gallery', function () { /* load and return images as object */ }); // Not sure about this dynamic subtemplating but oh well
}
// This now allows us to do the following:
function request(page, type) {
if (type == 'update') {
if (routes[page] != undefined && typeof routes[page] == 'function') {
respond(routes[page]());
}
}
else {
if (routes[page] != undefined && typeof routes[page] == 'function') {
var data = mergeArrays(routes['index'](), routes[page]());
// index.html which is just a Handlebars template
respond(data);
}
}
}
Here is a pattern I often use (in Express apps):
function respond(req, res, name, resource) {
if(req.accepts('json')) {
// Send JSON to clients who want it
res.send(resource);
} else {
// Render with layout only for non-XHR requests
resource.layout = !req.xhr;
res.render('resources/' + name, resource);
}
}
Example usage:
app.get('/images', function(req, res, next) {
getImages(function(err, images) {
if(err) return next(err);
respond(req, res, 'images', images);
});
});
app.get('/images/:id', function(req, res, next) {
getImage(req.params.id, function(err, image) {
if(err) return next(err);
respond(req, res, 'image', image);
});
});
image.jade:
img(src=uri, alt=title)
images.jade:
#gallery
for image in images
include image
Clients who ask for JSON get that, otherwise they get the full page only if it's a non-XHR request. XHR requests get just the HTML snippet for the requested resource. This works well for quite simple apps, where resources mostly correspond to pages.

Categories

Resources