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.
Related
I just coded sample files.
my ejs file display some data after receiving the data from API call.
my code is shown as below and the pattern of my code follows
node(router) --> call api(axios) --> display data on the ejs file.
//index.js
...
...
router.get('/dashboard', function(req,res,next){
try {
let result = await axios({ //Call API
method: 'get',
url: 'http://localhost:3001/user',
data: {
id: '1129',
lastName: 'Test'
}
});
res.render('dashboard', {data: result.data}); //display the received data
} catch (error) {
next(error)
}
})
module.exports = router;
//dashboard.ejs
...
...
<div>
<p>js data : <%=data%></p> //displays the data I jsut received from Axios
</div>
...
...
But what if some client types input value and I want to execute API call(post or put) with the client input value?
likes..
get client value from ejs --> send the value to node(router) --> call api(axios)
is there any way to do that?(without ajax, because I am trying not to use ajax).
You have three layers here. EJS is the least relevant one of these.
The controller (the function you pass to router.get) which runs on the server and handles the business logic.
The view (the EJS template) which runs on the server and handles the display logic (converting the data into HTML).
Client-side JS (<script> elements) which run on the client
But what if some client types input value and I want to execute API call(post or put) with the client input value?
Then you have two options:
Submit a <form> to a URL that is handled by a controller (which then uses axios server side, gets some data, populates an EJS view and returns a new page to the client).
Read the data with client-side JS, use Ajax to send it to a URL (which could be a URL you provide which is handled by a controller), have that controller return data (which could be HTML generated by EJS or plain JSON) and then use client-side JS to insert it into the page.
If you don't want to use Ajax, then you have to use a form submission and load a new page.
While it might be possible to call Axios from EJS (I have a feeling the asynchronous nature of it would break things) that is effectively the same as the form submission option, but it puts business logic in the view layer, which is confusing at best.
Related: What is the difference between client-side and server-side programming?
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.
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'm developing an Angular application with the MEAN stack, so suppose you got an express route that make a query to the databse, the results are sent in the response:
app.get('/api', function(req, res){
Todo.find({}, "", function(err,todos){
if (err)
res.send(err);
res.json(todos);
});
});
In the client-side:
Controller :
...
Todo.get().success(function(data){ //i got the service with the $http call
$scope.todos = data;
});
When I go to localhost:8080/#/api, I can see my partial and the data I requested.
The problem that I'm having is that if I omit the hashtag, i don't see the partial, I only see the response data in JSON format.
I also tried to use html5 mode, but if I reload I got the same behavior.
Any ideas on how can I avoid this behavior??
Anything after the # isn't sent to the server. So when you go to localhost:8080/#/api, expressjs just sees a request to / and returns the AngularJS template. AngularJS then routes the browser page using the /#/api, which called the Todo.get() and (I assume) makes a call to localhost:8080/api, returning the data from the DB.
That's why you only get the data when you omit the hash and when you use html5 mode.
I would suggest changing your API call to:
/api/todos - return data from the db
And change your AngularJS route to just use:
/todos - show the partial and data requested