I have an array of people as follows:
people = ['personA', 'personB', 'personC'];
I want to be able to display a page about the person based on the url. For example, localhost:3000/people/personA would direct me to a page about personA.
How do I do so without having to specify the following multiple times for each team member? Is there a way I can grab the part after '/people/'?
app.get('/people/personA', (req, res) => {
// render view for personA
}
});
You should do it with a parameter in the url. You can add a parameter using :param_here and get its value using req.params.param_here Like so:
app.get('/people/:person', (req, res) => {
var person = req.params.person; // Variable telling you which person to show
}
});
here is the solution
app.get('/people/:person', funcation (req, res){
res.render("views/"+req.params.person+".html");
}
});
Related
In my nodejs and "express" application I have this:
app.get("/:page?", function (req, res) {
var pg = req.params.page;
which corresponds to localhost:123 or localhost:123/3.
However, I want to be able to get the current page the same way by req.params.page, but the url should be localhost:123 or localhost:123/?page=X.
How?
My first suggestion is that you do not define your endpoint with /:variable. This will then match any route you create that follows that pattern. You should instead use something like /pages/:page to get a specific page
Then, you should use the URL parameter functionality in Express to include a URL parameter.
Define your route like this:
app.get("/pages/:page", function (req, res) {
var pg = undefined;
if (req.query.page) {
pg = req.query.page;
}
}
You can then access the page in req.query.page if it exists and do whatever you want with that value.
So for example, you could submit a request with localhost/pages/123?page=3.
req.query.page would equal 3 and req.params.page would equal 123.
You should instead define your route without the ? and if you do a get operation, for example on localhost:123/3?this=that then the req.query.this will be populated with the value that
I have an express route that handles localhost:3000/test. I want everything after this that doesn't have a period to render with the same router.get command. I'm struggling to figure out the correct Javascript regex string.
router.get('/test/:path[\s^.]*$', function () {
//res.render etc
}
So, when I visit localhost:3000/test/math or localhost:3000/test/math/geometry I want it to use the same route. But when I navigate to localhost:3000/test/math/geometry.test I want it to use a different route. I have used regex before just not sure how to combine it with the express params functionality.
EDIT: adeneo's idea will not work since I cannot chain my functions correctly using a check for a period. This is the point of regex, so that I check the url before I do the page logic.
Raul I'm afraid you have misunderstood the question. Let me try to state it more clearly.
I have a list of folders like this:
test
--folder1
----test1.js
----test2.js
----test3.js
--folder2
----folder2-1
----folder2-3
------test4.js
------test5.js
----test6.js
--folder3
The following urls should have one regex expression that captures them:
test/folder1
test/folder2
test/folder2/folder2-3
and another that only catches the following:
test/folder1/test1.js
test/folder2/folder2-3/test4.js
test/folder2/test6.js
Like I said, I have done regex, I just cannot figure out how to use the :paramName functionality of Express with it.
The order does matter in this case.
If you put first the exceptions yo will handled the path.
app.get('/test/math/geometry.test', function (req, res) {
res.send('catch it');
});
app.get('/test/:path*', function (req, res) {
res.send('the params are ' + JSON.stringify(req.params));
});
If you try this routes with for example ´/test/maths/dificults´ you can see in the end that req.params have something like:
{"0":"/maths/dificults","path":"maths"}
You can access to the raw param by position, in this case '0' because by name you have the params cut in the first '/'
EDIT
You can apply the same concept and use the real regular expression inside:
app.get(/\/test\/[^\.]*$/, function (req, res) {
res.send('catch it without dot');
});
app.get('/test/*', function (req, res) {
res.send('catch it with dot');
});
And you can use parentesis () to capture params in
req.params like //test/([^.]*)$/
I have difficult time to get latest bucket documents after any operation (insert/delete). I use node.js + express + couchbase, and here's my code, derived from its official website. it basically just a simple address book web-app and has three function: insert, show or delete contact.
After delete or insert operation, I use res.redirect("\") to reload my page. The problem is: it just show old data, only after I reload it for second time, it shows up. I just don't know what's wrong here. Can anybody help?
/* GET home page. */
router.get('/', function(req, res) {
var query = ViewQuery.from('view_people', 'by_id');
bucket.query(query, function(err, results){
return res.render('index', {people: results});
});
});
/* INSERT Contact here */
router.post('/insert', function(req, res){
var name = req.body.name;
var address = req.body.address;
var job = req.body.job;
var age = req.body.age;
bucket.insert(name, {
name : name,
address : address,
job : job,
age : age
}, function(err, reply){
if(err) return res.send(err);
return res.redirect('/');
})
});
/* REMOVE the contact */
router.get('/remove', function(req, res){
var id = req.query.id;
bucket.remove(id, function(err, response){
if (err) {return res.send(err);}
return res.redirect('/');
})
});
module.exports = router;
In Couchbase, views are eventually consistent and it looks like you are using views, thus the lag you are seeing. You'd be better off getting the document by key if you can, then Couchbase is strongly consistent. You'd get the most performance if you had a meta-data object that is a manual index of all of that user's contacts. Then when you want their contacts, you pull that meta-data object, then do a parallelized bulk get of the objects you want by key. That should perform VERY well and do the exact same thing. On top of that, you have a key pattern that uniquely identifies the object to the user.
Another option is to have a counter object per user that is a key value with just the counter. So For example have a key pattern
username::contacts::counter
Filled out, the object's key might look like
hernandez94::contacts::139
the counter would be the upper bound of the array of contacts for that user. to get the most recent contact, you just get the counter object, take that integer, construct the key and get exactly that object. It'd be very fast. To get all contacts, you get the counter object and then generate the keys to do a parallelized bulk get. Again, that'd be very fast. No querying, just raw speed that scales consistently.
Looks like you need to use stale=false in your view query . See : https://forums.couchbase.com/t/how-does-stale-query-work/870
I have a problem I can't find an answer to in Loopback's docs.
Say I have a model Company and a modelEmployee. There is an 1Xn relation between the Company and its Employees. When /api/Employees is called, server returns all the employees.
I only want to return the list of employees who are in the same company with the user requesting the list.
For this, I created a remote hook
Employee.beforeRemote('find', function(context, modelInstance, next) {
var reject = function() {
process.nextTick(function() {
next(null, false);
});
};
// do not allow anonymous users
var userId = context.req.accessToken.userId;
if (!userId) {
return reject();
}
//I get the details of the user who sent the request
//to learn which company does he belong to
Employee.findById(userId, function(err, user) {
if(!context.req.query.filter) context.req.query.filter={};
context.req.query.filter.where = {brandId:user.companyId};
console.log(context.req.query);
next();
});
});
I thought this should work every time, but appearantly it only works when find already has some query filters like include - although the console.log prints a correct context.req.query object.
What am I missing? Any help would be greatly appreciated!
context.args.filter seems to work for this purpose.
As a side note, instead of replacing where, you might want to merge it with something provided by client. For implementation idea you can refer to: https://github.com/strongloop/loopback-datasource-juggler/blob/master/lib/utils.js#L56-L122
How simultaneously to render a page and transmit my custom data to browser. As i understood it needs to send two layers: first with template and second with JSON data. I want to handle this data by backbone.
As i understood from tutorials express and bb app interact as follows:
res.render send a page to browser
when document.ready trigger jQuery.get to app.get('/post')
app.get('/post', post.allPosts) send data to page
This is three steps and how to do it by one?
var visitCard = {
name: 'John Smit',
phone: '+78503569987'
};
exports.index = function(req, res, next){
res.render('index');
res.send({data: visitCard});
};
And how i should catch this variable on the page- document.card?
I created my own little middleware function that adds a helper method called renderWithData to the res object.
app.use(function (req, res, next) {
res.renderWithData = function (view, model, data) {
res.render(view, model, function (err, viewString) {
data.view = viewString;
res.json(data);
});
};
next();
});
It takes in the view name, the model for the view, and the custom data you want to send to the browser. It calls res.render but passes in a callback function. This instructs express to pass the compiled view markup to the callback as a string instead of immediately piping it into the response. Once I have the view string I add it onto the data object as data.view. Then I use res.json to send the data object to the browser complete with the compiled view :)
Edit:
One caveat with the above is that the request needs to be made with javascript so it can't be a full page request. You need an initial request to pull down the main page which contains the javascript that will make the ajax request.
This is great for situations where you're trying to change the browser URL and title when the user navigates to a new page via AJAX. You can send the new page's partial view back to the browser along with some data for the page title. Then your client-side script can put the partial view where it belongs on the page, update the page title bar, and update the URL if needed as well.
If you are wanting to send a fully complete HTML document to the browser along with some initial JavaScript data then you need to compile that JavaScript code into the view itself. It's definitely possible to do that but I've never found a way that doesn't involve some string magic.
For example:
// controller.js
var someData = { message: 'hi' };
res.render('someView', { data: JSON.stringify(someData) });
// someView.jade
script.
var someData = !{data};
Note: !{data} is used instead of #{data} because jade escapes HTML by default which would turn all the quotation marks into " placeholders.
It looks REALLY strange at first but it works. Basically you're taking a JS object on the server, turning it into a string, rendering that string into the compiled view and then sending it to the browser. When the document finally reaches the browser it should look like this:
// someSite.com/someView
<script type="text/javascript">
var someData = { "message": "hi" };
</script>
Hopefully that makes sense. If I was to re-create my original helper method to ease the pain of this second scenario then it would look something like this:
app.use(function (req, res, next) {
res.renderWithData = function (view, model, data) {
model.data = JSON.stringify(data);
res.render(view, model);
};
next();
});
All this one does is take your custom data object, stringifies it for you, adds it to the model for the view, then renders the view as normal. Now you can call res.renderWithData('someView', {}, { message: 'hi' });; you just have to make sure somewhere in your view you grab that data string and render it into a variable assignment statement.
html
head
title Some Page
script.
var data = !{data};
Not gonna lie, this whole thing feels kind of gross but if it saves you an extra trip to the server and that's what you're after then that's how you'll need to do it. Maybe someone can think of something a little more clever but I just don't see how else you'll get data to already be present in a full HTML document that is being rendered for the first time.
Edit2:
Here is a working example: https://c9.io/chevex/test
You need to have a (free) Cloud9 account in order to run the project. Sign in, open app.js, and click the green run button at the top.
My approach is to send a cookie with the information, and then use it from the client.
server.js
const visitCard = {
name: 'John Smit',
phone: '+78503569987'
};
router.get('/route', (req, res) => {
res.cookie('data', JSON.stringify(pollsObj));
res.render('index');
});
client.js
const getCookie = (name) => {
const value = "; " + document.cookie;
const parts = value.split("; " + name + "=");
if (parts.length === 2) return parts.pop().split(";").shift();
};
const deleteCookie = (name) => {
document.cookie = name + '=; max-age=0;';
};
const parseObjectFromCookie = (cookie) => {
const decodedCookie = decodeURIComponent(cookie);
return JSON.parse(decodedCookie);
};
window.onload = () => {
let dataCookie = getCookie('data');
deleteCookie('data');
if (dataCookie) {
const data = parseObjectFromCookie(dataCookie);
// work with data. `data` is equal to `visitCard` from the server
} else {
// handle data not found
}
Walkthrough
From the server, you send the cookie before rendering the page, so the cookie is available when the page is loaded.
Then, from the client, you get the cookie with the solution I found here and delete it. The content of the cookie is stored in our constant. If the cookie exists, you parse it as an object and use it. Note that inside the parseObjectFromCookie you first have to decode the content, and then parse the JSON to an object.
Notes:
If you're getting the data asynchronously, be careful to send the cookie before rendering. Otherwise, you will get an error because the res.render() ends the response. If the data fetching takes too long, you may use another solution that doesn't hold the rendering that long. An alternative could be to open a socket from the client and send the information that you were holding in the server. See here for that approach.
Probably data is not the best name for a cookie, as you could overwrite something. Use something more meaningful to your purpose.
I didn't find this solution anywhere else. I don't know if using cookies is not recommended for some reason I'm not aware of. I just thought it could work and checked it did, but I haven't used this in production.
Use res.send instead of res.render. It accepts raw data in any form: a string, an array, a plain old object, etc. If it's an object or array of objects, it will serialize it to JSON for you.
var visitCard = {
name: 'John Smit',
phone: '+78503569987'
};
exports.index = function(req, res, next){
res.send(visitCard};
};
Check out Steamer, a tiny module made for this this exact purpose.
https://github.com/rotundasoftware/steamer
Most elegant and simple way of doing this is by using rendering engine (at least for that page of concern). For example use ejs engine
node install ejs -s
On server.js:
let ejs = require('ejs');
app.set('view engine', 'ejs');
then rename desired index.html page into index.ejs and move it to the /views directory. After that you may make API endpoit for that page (by using mysql module):
app.get('/index/:id', function(req, res) {
db.query("SELECT * FROM products WHERE id = ?", [req.params.id], (error, results) => {
if (error) throw error;
res.render('index', { title: results[0] });
});
});
On the front-end you will need to make a GET request, for example with Axios or directly by clicking a link in template index.ejs page that is sending request:
<a v-bind:href="'/index/' + co.id">Click</a>
where co.id is Vue data parameter value 'co' that you want to send along with request