Express res.render is not working and throwing exception.
It should render render a view and let the view engine send a response.
->res.send({'someKey': 'someValue'}) is working
-> res.render('viewName', {title: 'Home'}) is throwing exception from handlebars view engine - error Can't set headers after they are sent
It is also working as soon as we remove inversifyjs.
Let expressjs's view engine send the response. If InverseJs is sending the response after setting headers then there should be an option to define that inversejs is responsible for routing but not for sending responses. Although I'm not sure how it is working internally.
Rendering a view is common is express app when our app is not single page app and we want to render the view from server side.
Code for simple HomeController:
import { Request, Response, NextFunction } from "express";
import { injectable, inject } from "inversify";
import { interfaces, controller, request, response, httpGet, next } from "inversify-express-utils";
@controller("/home")
export class HomeController implements interfaces.Controller {
@httpGet("/")
private index(req: Request, res: Response) {
// res.send({"message": "Success" });
res.render("home", {
title: "Home"
});
}
}
_http_outgoing.js:491
throw new Error('Can\'t set headers after they are sent.');
^
Error: Can't set headers after they are sent.
at validateHeader (_http_outgoing.js:491:11)
at ServerResponse.setHeader (_http_outgoing.js:498:3)
at ServerResponse.header (F:\WitSpry\Source Code\Wisely\wisely\node_modules\express\lib\response.js:767:10)
at ServerResponse.contentType (F:\WitSpry\Source Code\Wisely\wisely\node_modules\express\lib\response.js:595:15)
at ServerResponse.send (F:\WitSpry\Source Code\Wisely\wisely\node_modules\express\lib\response.js:145:14)
at F:\WitSpry\Source Code\Wisely\wisely\dist\controllers\home.js:31:17
at Immediate._onImmediate (F:\WitSpry\Source Code\Wisely\wisely\node_modules\express-handlebars\lib\utils.js:26:13)
at runCallback (timers.js:810:20)
at tryOnImmediate (timers.js:768:5)
at processImmediate [as _immediateCallback] (timers.js:745:5)
+1
I had the same issue, wrapping the res.render() in a Promise worked, but not ideal.
Do you have an example in a controller of your solution? Or can we get this fix? This is currently stopping me from using inversify-express-utils at all! I need view engine support :/
Hi, in my solution all the controllers extend an abstract BaseController which has the custom render method. this is my code:
@injectable()
export abstract class BaseController {
public render(res: express.Response, template: string, options = {}): Promise<string> {
return new Promise<string>((resolve, reject) => {
res.render(template, options, (err, compiled) => {
if (err) {
console.log(err);
reject('500 when rendering the template');
}
resolve(compiled);
});
});
}
}
@controller('/')
export class ListingController extends BaseController {
constructor(@inject(TYPES.ApiService) private apiService: ApiService) {
super();
}
@httpGet('/')
public async get(
@request() req: express.Request,
@response() res: express.Response,
) {
// Do things...
const data: IListingData = await this.apiService.get(params);
return this.render(res, 'listing/listing', data);
}
}
I hope it helps!
This took me a while to find out. I was getting 204 responses with empty bodies even though I called res.render(). Even res.status(200).render() didn't help. @aescarcha Your solution still works, thanks for that
Most helpful comment
Hi, in my solution all the controllers extend an abstract BaseController which has the custom render method. this is my code:
I hope it helps!