Why is res.render() not doing changing the front-end? [duplicate] - node.js

I have basic express js application with following route:
router.get('/', function(req, res){
res.render('login');
});
It works fine - after logging into main page on my localhost, html from login.pug is nicely rendered on client side. However when my app runs, sometimes I want to render another pug file, when there already is html rendered on client side:
app.get('/dashboard', function(req, res){
res.render('dashboard', {user: req.query.login});
});
But when get request is send on'dashboard'path, nothing happens. As I understand, this happens because res.render just parses pug file into HTML and sends it to client as plain string (which I can inspect in browser developers tool, when I check AJAX response I see exactly rendered HTML).
Now my question is: is there a way to render HTML from res.render in client automatically? So on server side I just write res.render('template') and on client side page is re-rendered without handling the response?
I know I can clear whole DOM and append received string into document.body, I know also that I can make a POST form request and then page will be re-rendered automatically, but I want to avoid both solutions (don't ask why).
Thank you for help in advance.

When your Javascript sends an Ajax request, the response from that Ajax request is just returned back to your Javascript. That's it. The browser does not show anything. If you want to do something with that response, then it is the responsibility of your Javascript to do something with it (insert it in the page to show it, etc...).
If what you really want is that you want the browser to actually go to the /dashboard URL and then show that page, then your Javascript can just do:
window.location = '/dashboard';
This will tell the browser to fetch the contents of that URL, it will make a request to your server, your server will return the rendered HTML and the browser will display it in the page and show /dashboard as the URL in the browser bar. That should do everything you want.
So, it's totally up to your Javascript. Pick the right tool for the job. Either fetch data for your Javascript with an Ajax call and process the result in your Javascript or instruct the browser to load a new page. One or the other.
But when get request is send on'dashboard'path, nothing happens. As I understand, this happens because res.render just parses pug file into HTML and sends it to client as plain string (which I can inspect in browser developers tool, when I check AJAX response I see exactly rendered HTML).
Yes, that what Ajax requests do. They fetch content from the server and return the data back to your Javascript (and only to your Javascript).
is there a way to render HTML from res.render in client automatically?
Yes, use window.location = '/dashboard'; from your Javascript.
So on server side I just write res.render('template') and on client side page is re-rendered without handling the response?
Not from an ajax call. Ajax calls never automatically display content. Never. Ajax calls are programmatic requests that return data to your script. That's what they are. But, yes from Javascript you can cause content to be automatically displayed by setting window.location to a new URL.

Related

running function after res.send

I'm trying to run this code
module.exports = async (req, res, next) => {
res.set('Content-Type', 'text/javascript');
const response = {};
res.status(200).render('/default.js', { response });
await fn(response);
};
fn is a function that calls an api to a service that will output to the client something. but its dependent on the default.js file to be loaded first. How can do something like
res.render('/default.js', { response }).then(async() => {
await fn(response);
};
tried it, but doesn't seem to like the then()
also, fn doesn't return data to the client, it calls an api service that is connected with the web sockets opened by the code from default.js that is rendered.
do i have to make an ajax request for the fn call and not call it internally?
any ideas?
Once you call res.render(), you can send no more data to the client, the http response has been sent and the http connection is done - you can't send any more to it. So, it does you no good to try to add something more to the response after you call res.render().
It sounds like you're trying to put some data INTO the script that you send to the browser. Your choices for that are to either:
Get the data you need to with let data = await fn() before you call res.render() and then pass that to res.render() so your template engine can put that data into the script file that you send the server (before you send it).
You will need to change the script file template to be able to do this so it has appropriate directives to insert data into the script file and you will have to be very careful to format the data as Javascript data structures.
Have a script in the page make an ajax call to get the desired data and then do your task in client-side Javascript after the page is already up and running.
It looks like it might be helpful for you to understand the exact sequence of things between browser and server.
Browser is displaying some web page.
User clicks on a link to a new web page.
Browser requests new web page from the server for a particular URL.
Server delivers HTML page for that URL.
Browser parses that HTML page and discovers some other resources required to render the page (script files, CSS files, images, fonts, etc...)
Browser requests each of those other resources from the server
Server gets a request for each separate resource and returns each one of them to the browser.
Browser incorporates those resources into the HTML page it previously downloaded and parsed.
Any client side scripts it retrieved for that page are then run.
So, the code you show appears to be a route for one of script files (in step 5 above). This is where it fits into the overall scheme of loading a page. Once you've returned the script file to the client with res.render(), it has been sent and that request is done. The browser isn't connected to your server anymore for that resource so you can't send anything else on that same request.

how to render a file and send data to page in the same GET request

I am using angularjs on client-side and experss.js in server-side , i want to render a page and send data to the page (to fill a table) in the same get request
i tried using ejs engine to fill the table in the server-side and then render the page , but the problem with this solution is that the client-side (angularjs) cant access or manipulate the data.
other solution is (atrivial one) is to
make get request to get the page on cient-side
render the page on server-side
make another get request from client-side to get the data
send the data from server to client
The problem with this is that it contains two get requests.
Is there a possible way to render the page and send the data in one get request?
I am doing this to make the loading on site more efficient. Can i acheive more efficiency with one GET request ?
No, you can't. You can only have a single response to a given request. The browser is either expecting an HTML document or it is expecting JSON, it doesn't make sense to give it both at once. but you could render the page and send the data at the same time:
res.render('reports',{data:json});
and then access those data in the newly rendered page.
alternatively you could send a flag when making the call , and then decide whether you want to render or send based on this flag.
Or Ideally, it needs to be 2 separate route, one spitting json and other rendering a view. Else, you could pass a url param, depending on which you return json or render a view.
router.get('/reports/json', function(req,res){
var data = JSON_OBJECT;
res.send(data);
});
router.get('/reports', function(req,res){
var data = JSON_OBJECT;
res.render('path-to-view-file', data);
});
To access data in an AngularJS app without a second server request, include a .value script:
<script>
angular.module("myApp").value("myData",
<JSON data here>
}
</script>
Then in the controller, inject it:
app.controller("myCtrl", function($scope, myData) {
$scope.data = myData;
})
For more information, see
AngularJS angular.module API Reference - .value method
Could you please try using rout.getparam and pass values in route in the get request

Open browser popup on APIrequest nodejs express

I want to open a browser popup for client site on rest api request to nodejs backend.
I had tried
res.setHeader('Content-Type', 'text/html');
res.render('index', { title: 'Hey', message: 'Hello' });
But it still returning html codes as data to the client.
I also used window.open but window is not defined in server side
Is there anyway to make my backend redirect or render html form on api request!
the following image is how the client get response
If you want the browser change page/view, you need something like location.href = /yourview.html
If you want fill your popup with html built on the server, you need to get it using fetch or XMLHttpRequest or something built on top of them (for example axios, like you did) and then attach to the dom.
Once you got it, you can show the popup. But you are on the client side.
res.render return rendered html. http://expressjs.com/en/api.html#app.render

How can I send information from NodeJS server to client side?

For example, I want to signal to the client side that a username sent via the POST method in an HTML form already exists in my database.
I know how to recuperate POST data with body-parser and I know how to look it up in a MySQL database.
I know that I could use Ajax to write an error message directly on the form. What does my NodeJS server need to send and how does it send this information?
I've searched through numerous tutorials and I just found solutions where they send a new HTML page. I want to keep my web page the same and use functions like appendChild() to post the error message.
There are a couple of ways you could send data from server-side, so NodeJS, to client-side - which I assume in your case would be some JavaScript file like main.js that handles DOM manimulation.
So, the 1st way you could send data is through a templating engine like Handlebars, for example. There is an easy to use module for express you could get here: hbs.
Now to quickly summarize how an engine like that works, we are basically sending an HTML file like you probably saw in the tutorials, however, a templating engine like Handlebars allows us to send actual data with that file dynamically, so what we would do is render a specific Handlebars template (which in core is just HTML), and pass in a JavaScript object to the render call which would contain all the data you want to pass into that file and then access it in the .hbs file.
So on the server-side, we would write something like this, assuming we have a file called home.hbs and set up Handlebars as the templating engine:
router.get('/home', function(req,res) {
var dataToSendObj = {'title': 'Your Website Title', 'message': 'Hello'};
res.render('home',dataToSendObj);
});
And access in home.hbs like this:
<html>
<header>
{{title}}
</header>
<body>
message from server: {{message}}
</body>
</html>
Now, the issue with this approach is that if you wanted to update the data on the page dynamically, without having to reload the page, using a templating engine would not be ideal. Instead, like you said, you would use AJAX.
So, the 2nd way you could send data from your NodeJS server to the front-end of your website, is using an asynchronous AJAX call.
First, add a route to whatever route handler you are using for AJAX to make a call to. This where you have some logic to perhaps access the database, make some checks and return some useful information back to client.
router.get('/path/for/ajax/call', function(req,res) {
// make some calls to database, fetch some data, information, check state, etc...
var dataToSendToClient = {'message': 'error message from server'};
// convert whatever we want to send (preferably should be an object) to JSON
var JSONdata = JSON.stringify(dataToSendToClient);
res.send(JSONdata);
});
Assuming you have some file such as main.js, create an AJAX request with callbacks to listen to certain event responses like this:
var req = new XMLHttpRequest();
var url = '/path/for/ajax/call';
req.open('GET',url,true); // set this to POST if you would like
req.addEventListener('load',onLoad);
req.addEventListener('error',onError);
req.send();
function onLoad() {
var response = this.responseText;
var parsedResponse = JSON.parse(response);
// access your data newly received data here and update your DOM with appendChild(), findElementById(), etc...
var messageToDisplay = parsedResponse['message'];
// append child (with text value of messageToDisplay for instance) here or do some more stuff
}
function onError() {
// handle error here, print message perhaps
console.log('error receiving async AJAX call');
}
To summarize the above approach using AJAX, this would be the flow of the interaction:
Action is triggered on client-side (like button pressed)
The event handler for that creates a new AJAX request, sets up the callback so it knows what to do when the response comes back from the server, and sends the request
The GET or POST request sent is caught by our route handler on the server
Server side logic is executed to get data from database, state, etc...
The new data is fetched, placed into a JSON object, and sent back by the server
The client AJAX's event listener for either load or error catches the response and executes the callback
In the case of a successful response load, we parse the response, and update the client-side UI
Hope this is helpful!

node.js - express - render multiple views

I'ld like to send two successive ejs page to the client using the following code:
app.post('/', function(req,res) {
res.render('yourDemandIsBeingProceed.ejs');
//some code which require time (open an external programm, run a script, edit a response)
res.render('hereIsYourResult.ejs');
res.end();
});
So, once once the client post his form, he receives a page asking him to wait for a few seconds and then the page containing the response is send.
any suggestion?
many thx
What you can do is have client-side code in yourDemandIsBeingProceed.ejs when the page loads that performs a get/post request to a different endpoint. When the result from that is received, hide/show different elements inside yourDemandIsBeingProceed.ejs so it looks more like hereIsYourResult.ejs
What you really should do is have the user submit information via front end AJAX and put up a loading graphic until the JSON response gets back. AJAX was developed for situations exactly like this.

Resources