How to: Use ejs without express - node.js

I'm starting with node in general, and I'm attempting to do a site without express.
I would none the less want to use ejs to inject my html and this is where my problem is...
How do I attach the ejs.render(...) to the response?
PS: I know it might be a better option to use express, but I want to know how it works underneath before bridging it.
Something like:
var ejs = require("ejs");
function index (response, request, sequelize) {
response.writeHead(200, {"Content-Type": "text/html"});
test_data = "test data";
response.end(ejs.render("./views/home.html",test_data));
}
exports.index = index;
But that works ^_^
Thanks!

First of all, You need install ejs -> $ npm install ejs --save
Simple example:
main.ejs:
<p> <%= exampleRenderEjs %> </p>
server.ejs
var ejs = require('ejs');
var fs = require('fs');
var htmlContent = fs.readFileSync(__dirname + '/main.ejs', 'utf8');
var htmlRenderized = ejs.render(htmlContent, {filename: 'main.ejs', exampleRenderEjs: 'Hello World!'});
console.log(htmlRenderized);

There is a project called Consolidate.js which provides a common API for many template engines. This ensures they can all be interchangeable. If you want to render templates directly, you want to be compatible with this API.
Sample code from the Consolidate.js README:
var cons = require('consolidate');
cons.swig('views/page.html', { user: 'tobi' }, function(err, html){
if (err) throw err;
console.log(html); // Or write to your `res` object here
});
This sample is for Swig, but similar code works for EJS or any of the compatible engines.

Example from some book:
template.ejs
<html>
<head>
<style type="text/css">
.entry_title { font-weight: bold; }
.entry_date { font-style: italic; }
.entry_body { margin-bottom: 1em; }
</style>
</head>
<body>
<% entries.map(entry => { %>
<div class="entry_title"><%= entry.title %></div>
<div class="entry_date"><%= entry.date %></div>
<div class="entry_body"><%= entry.body %></div>
<% }); %>
</body>
</html>
function blogPage(entries) {
const values = { entries };
const template = fs.readFileSync('./template.ejs', 'utf8');
return ejs.render(template, values);
}
const server = http.createServer((req, res) => {
const entries = getEntries();
const output = blogPage(entries);
res.writeHead(200, {'Content-Type': 'text/html'});
res.end(output);
console.log('run server');
});
server.listen(8000);

Related

How to FTP upload a buffer (pdf buffer) using NodeJS?

I converted a HTML to pdf using html-pdf-node, but I am not find a way to store this PDF in my server using FTP.
My Code:
const html_to_pdf = require('html-pdf-node');
const generatePDF = () => {
// The test HTML file
let content = `
<html>
<head>
<title>Test Application</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css">
</head>
<body>
<div class="container">
<h2>Just a Test</h2>
</div>
</body>
</html>
`;
// generating the PDF
let options = {
format: 'letter',
margin: {
right: '40px',
left: '40px'
}
};
let file = { content };
html_to_pdf.generatePdf(file, options).then((pdfBuffer) => {
console.log(pdfBuffer); // This is the pdfBuffer. It works because if I send this buffer to my email as an attachment, I can open the PDF
// How can I create and store a test.pdf file inside my server using FTP connection?
});
}
Thank you
Using ftp should do it - https://www.npmjs.com/package/ftp
Installation: npm i ftp and usage something like:
const Client = require("ftp");
// snip snip some code here
html_to_pdf.generatePdf(file, options).then((pdfBuffer) => {
const c = new Client();
c.on("ready", function () {
c.put(pdfBuffer, "foo.pdf", function (err) {
if (err) throw err;
c.end();
});
});
const secureOptions = {
host: "localhost",
port: 21,
user: "TheGreatPotatoKingOfEurope",
password: "5uper_5eekrit!"
};
c.connect(secureOptions);
});

How to use packages in EJS template?

I'm trying to use timeago.js in an EJS template. I have tried to export the library like this:
src/lib/lib.js
const timeago = require('timeago.js');
exports.index = function(req, res){
res.render('links/list',{timeago: timeago});
}
The route is:
routes/links.js
router.get('/', (req, res)=>{
sequelize.query('SELECT * FROM links', {
type: sequelize.QueryTypes.SELECT
}).then((links)=>{
res.render('links/list', {links: links});
});
});
The EJS template is:
views/links/list.ejs
<div class="container p-4">
<div class="row">
<% for(i of links){ %>
<div class="col-md-3">
<div class="card text-center">
<div class="card-body">
<a target="_blank" href="<%= i.url %>">
<h3 class="card-title text-uppercase"><%= i.title %></h3>
</a>
<p class="m-2"><%= i.description %></p>
<h1><%= timeago.format(i.created_at); %></h1>
Delete Link
Edit
</div>
</div>
</div>
<% } %>
I need to use the library in the h1 to transform a timestamp I got from the database. However, I always get the same error: timeago is not defined.
How could I export Timeago correctly to use in EJS template? If I require the library in the routes file and send it to the EJS template through an object works perfectly, but not when I export it from another file.
I made the following test program to do a minimal test of timeago.js
const ejs = require('ejs');
const timeago = require('timeago.js');
let template = `
<% for(i of links){ %>
<h1> <%- i.created_at %>: <%- timeago.format(i.created_at) %> </h1>
<% } %>
`;
const renderData = {
links: [
{
created_at: new Date()
}
],
timeago
};
const output = ejs.render(template, renderData);
console.log(output);
Output:
<h1> Mon Sep 07 2020 00:01:57 GMT-0700 (Pacific Daylight Time): just now </h1>
So as long as you correctly pass the timeago object into your rendering data it will work.
The problem is likely here:
router.get('/', (req, res)=>{
sequelize.query('SELECT * FROM links', {
type: sequelize.QueryTypes.SELECT
}).then((links)=>{
res.render('links/list', {links: links});
});
});
Where you are not passing in the timeago object. This line:
res.render('links/list', {links: links});
Should probably be:
res.render('links/list', {links: links, timeago});
Edit:
More complete example using file paths specified in comments:
routes/links.js:
var express = require('express')
var router = express.Router();
const lib = require("../src/lib/lib");
router.get('/', (req, res)=>{
lib.index(req, res);
});
module.exports = router;
src/lib/lib.js
const timeago = require('timeago.js');
exports.index = function(req, res) {
const links = [
{
created_at: new Date()
}
];
res.render('links/list',{ timeago, links });
}

How to add img src attribute with VueJs

In my NodeJs route, I have the following:
router.get('/list/:id', function(req, res, next) {
request("http://localhost:3000/api/journal/" + req.params.id, function(error, response, body) {
var json = JSON.parse(body);
res.render('listdetail', { title: 'Journal', data: json });
});
});
The data is a json object containing all my screen fields. One of the fields is a base64 presentation of an image.
Then, in my List Detail html I have the following:
<div id="app">
<img class="materialboxed" src="{{data.base64Image}}" width="200">
</div>
This is surely not working... How can I add to the src attribute the base64 information that was sent by NodeJS?
I tried also the following:
<img class="materialboxed" :src=imagebase64Source width="200">
<script type="text/javascript">
var app = new Vue({
el: '#app',
data: {
imagebase64Source: {{data.base64Image}}
}
})
</script>
But it obviously does not work
Thanks
EDIT:
Strange, it's working now!
Here's what I've done:
<img class="materialboxed" src="{{ data.base64Image }}" width="200">
The only difference I can see is the spacing between the mustache.
Thanks to all who helped.
You can do it simply like this:
<template>
<div>
<img :src="image"/>
</div>
</template>
<script>
module.exports = {
data: function() {
return {
image: //your b64 string there
};
}
};
</script>
Pay attention by the way, depending on what you have on your string, you may have to add a header to the raw string.
<template>
<div>
<img :src="imgWithHeader"/>
</div>
</template>
<script>
module.exports = {
data: function() {
return {
image: //your b64 string there
};
},
computed: {
imgWithHeader() {
return 'data:' + MIMETypeOfTheImage + ';base64,' + this.image;
}
}
};
</script>
Of course you should figure out what is the type of the image, in this case.
I think the method you tried should work if the syntax is corrected
So this:
<img class="materialboxed" :src=imagebase64Source width="200">
<script type="text/javascript">
var app = new Vue({
el: '#app',
data: {
imagebase64Source: {{data.base64Image}}
}
})
</script>
should be changed to this:
<img class="materialboxed" :src="imagebase64Source" width="200">
<script type="text/javascript">
var app = new Vue({
el: '#app',
data () {
return {
imagebase64Source: data.base64Image,
}
}
})
</script>

React and Socket.io

I'm trying to create a simple app using ReactJS and Socket.io
In my component I want to be able to communicate with the server, but the problem is that I don't know how to do io.connect()
1.Do I need to explicitly specify the IP address like io.connect("http://myHost:7000") or is it enough to say : io.connect() ? As we can see in this piece of code :
https://github.com/DanialK/ReactJS-Realtime-Chat/blob/master/client/app.jsx
2.I do more or less the same as this code , but I receive error when I do npm start as io is undefined. I think , io is provided globally by including the socket.io script. How can I solve this problem ?
'use strict';
var React = require('react');
var socket = io.connect();
var chatWindow = React.createClass({
displayName: 'chatWindow',
propTypes: {},
getDefaultProps: function() {
return ({
messages: 0
});
},
componentDidMount: function() {
socket = this.props.io.connect();
socket.on('value', this._messageRecieve);
},
_messageRecieve: function(messages) {
this.setState({
messages: messages
});
},
getInitialState: function() {
return ({
messages: 0
});
},
_handleSend: function(){
var newValue = parseInt(this.refs.messageBox.value) + this.props.messages;
this.setState({
messages: newValue
});
socket.emit('clientMessage', { message: newValue});
},
render: function() {
var window =
<div>
<div>{this.props.messages}</div>
<input type="text" id="messageBox" refs="messageBox"></input>
<input type="button" onClick={this._handleSend} value="send" id="send"/>
</div>;
return (window);
}
});
module.exports = chatWindow;
This is the code :
https://github.com/arian-hosseinzadeh/simple-user-list
Answers:
1) No, you don't need to specify the IP, you can even use / and it will go through the default HTTP 80 port, anyway, you can find more examples on the socket.io site.
2) Require io too, remember to add socket.io-client to your package:
var React = require('react'),
io = require('socket.io-client');
Anyway, if you want to include the client script that socket.io server provides as a static file, then remember to add it into your HTML using a <script/> tag, that way you'll have io on the global scope avoiding the require part, but well, I prefer to require it.
NOW, WHAT ABOUT...
Trying my lib: https://www.npmjs.com/package/react-socket
It will handle the socket connection on mount and disconnection on unmount (the same goes for socket event listeners), give it a try and let me know.
Here you have an example:
http://coma.github.io/react-socket/
var App = React.createClass({
getInitialState: function() {
return {
tweets: []
};
},
onTweet: function(tweet) {
var tweets = this
.state
.tweets
.slice();
tweet.url = 'https://twitter.com/' + tweet.user + '/status/' + tweet.id;
tweet.at = new Date(tweet.at);
tweet.avatar = {
backgroundImage: 'url(' + tweet.img + ')'
};
tweets.unshift(tweet);
this.setState({
tweets: tweets
});
},
renderTweet: function (tweet) {
return (
<li key={tweet.id}>
<a href={tweet.url} target="_blank">
<div className="user">
<div className="avatar" style={ tweet.avatar }/>
<div className="name">{ tweet.user }</div>
</div>
<div className="text">{ tweet.text }</div>
</a>
</li>
);
},
render: function () {
return (
<div>
<ReactSocket.Socket url="http://tweets.socket.io"/>
<ReactSocket.Event name="tweet" callback={ this.onTweet }/>
<ul className="tweets">{ this.state.tweets.map(this.renderTweet) }</ul>
</div>
);
}
});
React.render(<App/>, document.body);

Nodejs EJS helper functions?

Is there a way to register helper functions to EJS templates, so that they can be called from any EJS template? So, it should work something like this.
app.js
ejs.helpers.sayHi = function(name) {
return 'Hello ' + name;
});
index.ejs
<%= sayHi('Bob') %>
Yes, in Express 3 you can add helpers to app.locals. Ex:
app.locals.somevar = "hello world";
app.locals.someHelper = function(name) {
return ("hello " + name);
}
These would be accessible inside your views like this:
<% somevar %>
<% someHelper('world') %>
Note: Express 2.5 did helpers differently.
I have another solution to this, and I think it has some advantages:
Don't polute your code exporting filters.
Access any method without the need to export them all.
Better ejs usage (no | pipes).
On your controller:
exports.index = function(req, res) {
// send your function to ejs
res.render('index', { sayHi: sayHi });
}
function sayHi(name) {
return 'Hello ' + name;
};
Now you can use sayHi function inside your ejs:
<html>
<h1><%= sayHi('Nice Monkey!') %></h1>
</html>
You can use this method to send modules to ejs, for example, you could send 'moment' module to format or parse dates.
Here's an example filter...I'm not familiar with helpers.
var ejs = require('ejs');
ejs.filters.pluralize = function(num, str){
return num == 1 ? str : str+'s';
};
<%=: items.length | pluralize:'Item' %>
Will produce "Item" if it's 1, or if 0 or > 1, produces "Items"
app.js
ejs.filters.sayHi = function(name) {
return 'Hello ' + name;
});
index.ejs
<%=: 'Bob' | sayHi %>
I am using:
In helpers/helper.js
var func = {
sayhi: function(name) {
return "Hello " + name;
}, 
foo: function(date) {
//do somethings
}    
};
module.exports = func;
In router:
router.get('/', function(req, res, next) {
res.render('home/index', {
helper: require('../helpers/helper'),
title: 'Express'
});
});
In template:
<%= helper.sayhi("Dung Vu") %>
goodluck

Resources