I'm making a little bit complex page using EJS and Express.JS. I'll simplify it a little:
First application loads /update the easy way and renders it:
app.get('/update', (req, res) => {
res.render('update');
});
update in render function is an EJS template. Here's how it looks like:
...
<div id="progress"></div>
<button id="perform" type="button" class="btn btn-default">Download & Update</button>
<script>
$('#perform').click(function() {
$('#perform').hide();
$('#progress').load('/perform');
});
</script>
...
As you can see on button click, application loads /perform express.js route into specific div. Here's what it does on Node.JS side:
app.get('/perform', function(req, res) {
//Renders div
res.render('perform')
//Does some actions in 1-2 minues.
//Here I want it to redirect to / of application.
});
After it returns some content using res.render(), application starts doing some processes. They take about 1 minute and after completion I want application to redirect to /. I've tried using res.redirect('/') e.t.c., but nothing works. Maybe somehow it should tell browser to redirect..
What can I do here?
You load "/perform" via ajax, so you can only send a response (which you do with the res.render('perform'))
So you should do the redirect client side
You can do this with polling, a timeout or even better, you could use socket.io to give a signal from server to client when the actions are done.
Related
In index.js I am rendering page with global variables.
router.get('/index', function(req, res, next) {
res.render('index', { title: 'RLH',
countNumber: countNumber,
countReleased: countReleased,
countOpen: countOpen
});
in the same index.js I also have:
router.post('/index', function(req, res, next) {
datatamper = req.body;
countSev();
countTickets();
countTime();
});
On port 3000 I am listening for data, once I get it I am making some calculation and then the page is ready to be opened with global variables.
Clearly this is working just fine to open the page and all data will be here
On the page I am presenting data like that:
<p> <b> Tickets</b>: <span>{{countNumber}}</span></p>
Yet I would like to update just the data on the website by itself after every post(not refreshing the whole page).
Data by post is coming every minute, yet that might change.
You need to implement either some form of longpolling, where your javascript frontend sends requests to the api every so often to check for updates, and then adds them to the page, or use a technology like websockets to get the data as it's updated.
I'm trying to make an application using nodejs, express and ejs. What I'm aiming to do is submitting a form to the server, trigger a server function which processes the data to get some result, and getting my page to display the result without reloading the whole page.
Currently this is what I have:
ejs
<form method = "GET" action = "/sendinput"
...something here
</form>
app.js
app.get('/sendinput', function (req, res) {
result = processData(req.query);
});
I manage to get the function to run when the form is submitted, but after that the page keeps loading even after the function finishes running. I'm also not sure how to fetch the result and let the form segment of the html displays it without reloading the whole page.
To stop the page from loading, use res.end();
it will signal the server that your function is done.
app.get('/sendinput', function (req, res) {
result = processData(req.query);
res.end();
});
So in the end I solve it by using Ajax, which doesn't prompt the page for a reload and manage to get what I want.
I am currently trying to develop a NodeJS application, which contains 3 main Routes:
app.get('/1',(req, res) => {
res.sendFile(path.join(__dirname, './index.html'))
});
app.post('/1',(req, res) => {
model.sharetime(req.body.zeit);
});
and
app.get('/receive', (req, res) => {
res.json(model.receivetime());
});
The post Route /1 will be called once ever second, which receives a value that is put into an array.
The problem that I encounter is, each time I want to call the route /receive while the /1 get route is open, there is no response whatsoever,
after I restart the server, suddenly I get the response that I requested.
Which basically means, I cant have the route /1 which opens my index file open which I need for the application to post results back to the server and simultaneously receive the updated values via the route /receive.
Please help :)
You're not responding to the request, you're merely calling a function with a value from the posted form. Add at least a res.end(); to that route handler.
I have a post route that looks something like this:
router.post('/:name/book', function(req, res){
Booking.create(myNewBooking, function(err, booking){
if(err){ return next(err); }
//What am I supposed to do here? I usually do:
req.app.locals.booking = booking;
res.render('booking_success.jade');
});
});
The problem: If the user refresh after doing this post request, they send the same data again. I don't want that to be possible. What is the best way to prevent this? I thought of this:
router.post('/:name/book', function(req, res){
Booking.create(myNewBooking, function(err, booking){
if(err){ return next(err); }
res.redirect('/booking-success');
});
});
router.get('/booking-success', function(req, res){
res.render('booking_success.jade');
});
Is this the way to go? Or are there better ways to do this?
Both of these options are done regularly. The reason to choose the redirect over the render is purely based on what you want to happen after the post.
If this is an API called by some external script (either Javascript via Ajax or any outside agent), then you should just render an acceptable (and probably small) response, often a simple piece of JSON.
If this is a form submission from a browser web page and you want the URL in the browser to end up on something that matches the rendered content, then a redirect makes great sense.
If this is a form submission, either option will clear the form from the browser and prevent a simple repost of the same data.
Though you can use both of the methods but looking at the above case you don't need to do res.redirect() and then res.render() you can directly do res.render() from the first route itself.
res.redirect() will be useful if you have routes which you can hit directly or via a redirect so that you don't have implement the same logic again in two places.
I currently have an app which uses Express with Jade templates.
I'm building a new version of the app using Angular with client-side HTML.
I need access to certain request parameters in order to determine user permissions in my Angular code. My problem is that I don't know how to get ahold of these parameters in my Angular controllers/services.
Below is what currently occurs in Express with the Jade structure:
routes.js:
router.get('/player/:id',
playerRoute.show
);
player.js:
var show = function(req, res) {
res.render('player', {user: req.user});
};
...and now my new version's handler:
var player = function(req, res) {
//res.sendFile(path.join(__dirname, '../v2', 'index.html'));
res.json({user: req.user});
};
The correct user JSON is sent back to my client-side with the code above. When res.json is commented out and res.sendFile uncommented the correct HTML is rendered. My dilemma is how to both render this HTML AND provide my client-side Angular code with the user JSON object?
After all that, your question just boils down to:
MY dilemma is how to both render this HTML AND provide my client-side Angular code with the user JSON object?
You don't. The usual case is to just render the HTML along with the assets needed to render the initial app (hide everything, show a splash screen whatever). Further data (like getting your user) is handled by API calls to your server via Angular's HTTP facilities. That means they are separate. After that API call, your app determines what to render.
Otherwise, you could just render the data in the HTML as some global variable and have Angular pick it up from there. This is messy IMO, but doesn't require a separate API call to get the data.
copied from my own answer to a similar question
To get a variable from server to client javascript try templating a json string into the html and loading it from the javascript. EJS handles quote escaping and I think Jade does too. For reference content!= safeString tells Jade to skip escaping, so does content !{safeString}.
- var user={id:1, displayName:'foo'}
#example
meta(data-userJSON=JSON.stringify(user))
script(src="//code.jquery.com/jquery-1.11.3.min.js")
script.
var user = JSON.parse(
$('#example meta').attr('data-userJSON')
)
console.log(user);
span #{user.id}
span #{user.displayName}
Here's how I ended up handling this situation. I simply created a new API endpoint which I can easily hit with an Angular service. Here's the Node setup:
routes.js:
router.get('/currentUser',
apiController.currentUser.index
);
currentUser.js:
var index = function(req, res) {
res.json({user: req.user});
};
module.exports = {
index: index
};
Still seems odd to me to make an API call to get the request parameters, but it works. Feedback appreciated.