node js pass / send post data to html - node.js

Hello i'm new to node js and i am trying send / pass post data to html but i can't seem to get it to work And was hoping maybe someone could point me in the right direction on how i can.
Server code:
const express = require("express");
const bodyParser = require('body-parser');
const app = express();
app.use(express.static("public"));
app.use(bodyParser.urlencoded({ extended: true }));
app.get("/", (request, response) => {
response.sendFile(__dirname + "/views/index.html");
});
app.post('/sendInfo', (req, res) => {
try {
console.log(`firstname: ${req.body.firstname} lastname: ${req.body.lastname}.`);
var firstName = req.body.firstname,
lastName = req.body.lastname;
res.sendFile(__dirname + "/views/info.html", { fistname: firstName, lastname: lastName });
} catch (e) {
console.error("error", e);
}
});
const listener = app.listen(process.env.PORT, () => {
console.log("Your app is listening on port " + listener.address().port);
});
views/info.html code:
<html>
<head>
<title>My Site title</title>
</head>
<body>
<h1><%= fistname %></h1>
<h1><%= lastname %></h1>
</body>
</html>

Looks like you are using the EJS template engine. So, there are a number of things that are missing in your code.
You need to tell express that you are using EJS at the template engine
The view must have an extension of .ejs not .html
You should be using res.render() and pass in the template name and the JSON data which will be used in the template
Set up a Node.js project using npm init -y, then run npm install express ejs, then create the app.js file (code given below) and finally create the views/index.ejs file (code given below). The views directory should be at the same level as your node_modules directory.
// app.js
const express = require('express');
const bodyParser = require('body-parser');
const port = process.env.PORT || 3006;
const app = express();
app.use(express.static(__dirname + '/build'));
app.use(express.json())
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json({ extended: true }));
app.set('view engine', 'ejs');
app.get('/fn/:first_name/ln/:last_name', (req, res) => {
res.render('index', {
first_name: req.params.first_name,
last_name: req.params.last_name
});
});
app.listen(port, () => {
console.log(`App listening on port ${port}`);
});
// views/index.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div>First name is <%= first_name %></div>
<div>Last name is <%= last_name %></div>
</body>
</html>
Your package.json file must look something like this, use the start script
{
"name": "node-template",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "node app.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"ejs": "^3.1.5",
"express": "^4.17.1"
}
}
Run the app using npm start
Finally, open up a browser and hit http://localhost:3006/fn/John/ln/Doe
If all goes well you will see an html rendered in the browser like this...
First name is John
Last name is Doe
Output:
Good luck.
Note: For the sake of simplicity I used GET instead of POST and used path params instead of request body. But the template engine works the same way.

Related

aws amplify lambda function ReactDOMServer.renderToString error

I am building an app similar to amazon using:
expo and react-native
aws-amplify
I want to be able to print shopping cart using Expo Print API (imagine with the app, click the "print" button prints all items from your shopping cart into a pdf). The Print API takes a HTML string as input.
There are 2 ways to generate a HTML for the shopping cart: First, hardcode it in a javascript string. This approach is painful and too old school.
const html = cart => `
<!doctype html>
<html lang="en">
<head>
...
</head>
<div>
<h1>${cart.name}</h1>
...
</div>
`
Or utilize some tool to convert a (much easier to write) react component to a HTML - react-dom-server looks the right tool. However, react-dom-server can only be used in server side instead of client side, so I try to leverage lambda function that integrates well with aws-amplify.
These are what I tried:
add amplify function
$ amplify function add
Using service: Lambda, provided by: awscloudformation
? Provide a friendly name for your resource to be used as a label for this category in the project: renderReact
? Provide the AWS Lambda function name: renderReact
? Choose the function template that you want to use: Serverless express function (Integration with Amazon API Gateway)
? Do you want to access other resources created in this project from your Lambda function? No
? Do you want to edit the local lambda function now? Yes
Please edit the file in your editor: /Users/evan/source/inventoryapp-mobile/amplify/backend/function/renderReact/src/index.js
? Press enter to continue
Successfully added resource renderReact locally.
edit amplify/backend/function/renderReact/src/app.js
import React from "react";
import ReactDOMServer from 'react-dom/server';
var express = require("express");
var bodyParser = require("body-parser");
var awsServerlessExpressMiddleware = require("aws-serverless-express/middleware");
// declare a new express app
var app = express();
app.use(bodyParser.json());
app.use(awsServerlessExpressMiddleware.eventContext());
// Enable CORS for all methods
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header(
"Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept"
);
next();
});
app.get("/render", function(req, res) {
const reactDom = ReactDOMServer.renderToString(<div>hello world</div>);
res.json({ success: htmlTemplate(reactDom), url: req.url });
});
function htmlTemplate(reactDom) {
return `
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>React SSR</title>
</head>
<body>
<div id="app">${reactDom}</div>
</body>
</html>
`;
}
app.listen(3000, function() {
console.log("App started");
});
// Export the app object. When executing the application local this does nothing. However,
// to port it to AWS Lambda we will create a wrapper around that will load the app from
// this file
module.exports = app;
edit amplify/backend/function/renderReact/src/package.json
{
"name": "renderReact",
"version": "1.0.0",
"description": "",
"main": "index.js",
"dependencies": {
"aws-serverless-express": "^3.3.5",
"body-parser": "^1.17.1",
"express": "^4.15.2",
"react": "^16.10.1",
"react-dom": "^16.10.1"
},
"devDependencies": {},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
cd amplify/backend/function/renderReact/src && yarn install
edit amplify/backend/function/renderReact/src/event.json
{
"httpMethod": "GET",
"body": "{\"name\": \"Amplify\"}",
"path": "/render",
"resource": "/{proxy+}",
"queryStringParameters": {}
}
cd back to project root, run function but err
$ amplify mock function renderReact
Using service: Lambda, provided by: awscloudformation
? Provide the name of the script file that contains your handler function: index.js
? Provide the name of the handler function to invoke: handler
? Provide the relative path to the event: event.json
Testing function locally
/Users/evan/source/inventoryapp-mobile/amplify/backend/function/renderReact/src/app.js:24
const reactDom = ReactDOMServer.renderToString(<div>hello world</div>);
^
SyntaxError: Invalid or unexpected token
at Object.Module._extensions..js (internal/modules/cjs/loader.js:947:10)
Note that I am not trying to render my <ShoppingCart /> component, just try to render the simplest <div>hello world</div> react component but no luck.
Any help? Thanks.

express-validator and populating an input field after an error

I'm relatively new to node and express, and have come across a problem I can't seem to solve.
I've created a SSCCE which tries to take two inputs, name and height, and if there's a validation error render the same page again with those values.
If I enter '2.2.2' into the height field (obviously not a float), the value is not re-rendered. If I change the height input to type="text", the field is rendered with the previous value. All other fields of type text behave as expected.
I've put 'novalidate' on the form, but is this a quirk with the number input type? Or have I made a simple mistake?
(I'm also slightly confused as to why 'isFloat()' accepts '2' as valid)
Any help would be appreciated
app.js
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const { check } = require('express-validator/check');
const { validationResult } = require('express-validator/check');
app.use(bodyParser.urlencoded({ extended: false }));
app.set('view engine', 'ejs');
app.set('views', 'views');
app.get('/', (req, res, next) => {
res.render('test', {
pageTitle: 'Test',
hasError: false,
validationErrors: []
})
});
app.post('/',
[
check('name', 'Name must be at least 2 letters in length')
.isLength({min: 3}),
check('height', 'Height must be a float')
.isFloat()
] ,
(req, res, next) => {
const errors = validationResult(req);
if(!errors.isEmpty()){
console.log(errors.array());
return res.render('test', {
pageTitle: 'Error',
hasError: true,
validationErrors: errors.array(),
person: {
name: req.body.name,
height: req.body.height
}
})
} else {
res.send(`Person created: ${req.body.name}, height: ${req.body.height}`);
}
});
app.listen(3000);
test.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title><%= pageTitle %></title>
</head>
<body>
<div class="errorMessage"><%= validationErrors.length > 0 ? validationErrors[0].msg:'' %></div>
<form action="/" class="test-form" method="POST" novalidate>
<label for="name">Name</label>
<input type="text" name="name" id="name" value="<%= hasError ? person.name:'' %>">
<label for="height">Height</label>
<input type="number" name="height" id="height" value="<%= hasError ? person.height:'' %>">
<button class="submit">Submit</button>
</form>
</body>
</html>
package.json
{
"name": "test",
"version": "1.0.0",
"description": "",
"main": "app.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"ejs": "^2.6.1",
"express": "^4.16.4",
"express-validator": "^5.3.1"
}
}
I gave up on this. There didn't seem to be any way to get an input field of type number to submit an invalid value, even with novalidate.
So I just changed the type to text.

How to get text from iframe of Dialogflow Web Demo

I'm trying to extract the server-response text from the in iframe of Dialog Web Demo
Here's my code- Currently, the output is null:
<!DOCTYPE html>
<html lang=\"en\">
<head><meta name=\"viewport\" content=\"width=device-width, initial- scale=1, user-scalable=no\"/>
<title>Dialog</title>
</head>
<body>
<div align="center">
<iframe
id="dialog"
allow="microphone;"
width="350"
height="430"
src="https://console.dialogflow.com/api-client/demo/embedded/xxxxxxxxxxxxxxxxxxxxxxxxxxx">
</iframe>
</div>
<div align="center">
<script>
var dialogFrame = document.getElementById("dialog");
var dialogDocument = dialogFrame.contentWindow.document;
var dialogResponse = dialogDocument.getElementById("server-response");
document.write(dialogResponse);
</script>
</div>
</body>
</hmtl>
I'm expecting to extract text responded by Dialogflow, but the result is null.
Data cannot be retrieved from the HTML <iframe> element, which is only a display block. Data can be retrieved through API call; in Dialogflow, you get this data with Fulfillments.
Check below flow to deploy a Node app on App Engine, serving a Dialogflow Chat at the default endpoint, and posting fulfillment data at /fulfillment endpoint.
A) Configure fulfillment
Pay attention to the following:
URL: input your HTTPS Express POST endpoint (e.g. https://[PROJECT_ID].appspot.com/fulfillment)
leave all other fields blank
Domains: Enable webhook for all domains
Once created and saved, you still need to enable fulfillment for each Intent (and their follow-up if any) that you are using
B) Application
Create a Node App in App Engine from the console
Then deploy this app, replacing the <iframe> with yours:
app.yaml
runtime: nodejs8
package.json
{
"dependencies": {
"actions-on-google": "^2.5.0",
"dialogflow-fulfillment": "^0.5.0",
"express": "^4.16.4"
},
"scripts": {
"start": "node index.js"
}
}
index.js
'use strict';
const {WebhookClient} = require('dialogflow-fulfillment');
const express = require('express');
const bodyParser = require('body-parser');
var path = require('path');
const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
function WebhookProcessing(req, res) {
const agent = new WebhookClient({request: req, response: res});
console.log('Dialogflow Request headers: ' + JSON.stringify(req.headers));
console.log('Dialogflow Request body: ' + JSON.stringify(req.body));
console.log(JSON.stringify(req.body.queryResult.queryText));
console.log(JSON.stringify(req.body.queryResult.fulfillmentText));
}
app.get('/', (req, res) => {
res.sendFile(path.join(__dirname + '/index.html'));
});
app.post('/fulfillment', function (req, res) {
WebhookProcessing(req, res);
});
const PORT = process.env.PORT || 8080;
app.listen(PORT, () => {
console.log(`Server listening on port ${PORT}...`);
});
index.html
<!DOCTYPE html>
<html lang=\"en\">
<head><meta name=\"viewport\" content=\"width=device-width, initial- scale=1, user-scalable=no\"/>
<title>Dialog</title>
</head>
<body>
<div align="center">
<iframe
allow="microphone;"
width="350"
height="430"
src="https://console.dialogflow.com/api-client/demo/embedded/xxxxxxxxxxxxxxxxxxxxxxxxxxx">
</iframe>
</div>
</body>
</hmtl>
When user starts a conversation in the chat, the function WebhookProcessing outputs the logs of the body and header of each request (each message sent by user), and extracts and logs the values of both fields queryText (user's message) and fulfillmentText (Bot's reply).
Note that this is just an example of integration in App Engine, you could also consider deploying a Cloud Function, and if you work with a Firebase database, then you can use the inline editor and deploy the function from Dialogflow.

How to use Electron with an existing Express application

I read and tried samples like the one on https://github.com/frankhale/electron-with-express but still I don't understand how to convert an Express app into Electron
How can I use Electron with an existing Express application?
Take for example this Express application:
app.js
var express = require("express");
var app = express();
var request = require("request");
app.set("view engine", "ejs");
app.get("/", function(req, res) {
res.render("search");
});
app.get("/results", function(req, res){
var query = req.query.search;
var url = "https://yts.am/api/v2/list_movies.json?sort=seeds&limit=15&query_term='" + query + "'";
request(url, function(error, response, body){
var data = JSON.parse(body);
if(!error && response.statusCode == 200){
//res.send(data["data"]["movies"][0]["title"]);
res.render("results", {data: data});
//["movies"][0]["title"]
}
else
console.log(data);
});
});
app.listen(process.env.PORT, process.env.IP, function(){
console.log("IMDB server has started");
});
search.ejs
Search for a movie
<form action="results" method="GET">
<input type="text" placeholder="search term" name="search">
<input type="submit">
</form>
results.ejs
Results page
<ul>
<% data["data"]["movies"].forEach(function(movie){ %>
<li>
<strong><%= movie["title"]%></strong> - <%= movie["year"]%>
</li>
<% }) %>
</ul>
Search again
In the Electron main.js file, you should require your app.js file to start the Express application, then create a new instance of BrowserWindow and load the URL that your Express application is listening on.
Note that you'll either have to hard code the IP and PORT in Electron, or export them from Express and import them into the Electron main.js script.
./main.js
const { BrowserWindow, app } = require('electron')
require('./app.js')
let mainWindow = null
function main() {
mainWindow = new BrowserWindow()
mainWindow.loadURL(`http://localhost:3000/`)
mainWindow.on('close', event => {
mainWindow = null
})
}
app.on('ready', main)
./package.json
{
"name": "your-app-name",
"version": "1.0.0",
"description": "A description of your application",
"main": "main.js",
"scripts": {
"start": "electron ."
},
"repository": "https://github.com/link/to/repo",
"keywords": [ "some","keywords" ],
"author": "You",
"license": "Your License",
"dependencies": {
"ejs": "^2.6.1", // required for your specific example where `ejs` package is used
"electron": "^3.0.9",
"express": "^4.16.4"
}
}
Then you'll want to make sure that the node_modules directory is in the same directory as main.js and package.json.
Finally, you can start your Express/Electron application using:
> npm start
If your Express application is not in the same directory as Electron, you will have to set the views directory for express accordingly:
app.js
var path = require('path')
var request = require("request");
var express = require("express");
var app = express();
app.set('views', path.join(__dirname, '/views'));
...
Where /views is a directory relative to app.js that contains your views.

Why does my swig template not render in my MEAN web app?

I am trying to learn the MEAN stack along with Swig templates. I’m coding from scratch, as I tried a MEAN framework but it generated a lot of files and it was too much for me to begin with.
Currently my Swig template index.html does not render the HTML. This is the output I am getting:
{% include 'header.html' %}
<br>Welcome to my test website
where as I am expecting following
This is coming from Header
<br>Welcome to my test website
Why is it not rendering?
Following is my folder structure:
--config
-config.js
--node_modules
-* //modules installed via npm link
--public
-header.html
-index.html
-package.json
-routes.js
-server.js
Below is the content of each file
config.js
var port = process.env.PORT || 8080;
module.exports = {
dburl: 'mongodb://localhost/test',
port: port,
templateEngine: 'swig'
}
header.html
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<p> This is coming from Header</p>
index.html
{% include 'header.html' %}
<p>Welcome to my test website</p>
</body>
package.json
{
"name": "test",
"version": "0.0.1",
"author": "Rukmaj Chandavar",
"dependencies": {
"express": "*",
"mongoose": "*",
"angular": "*",
"swig": "*",
"consolidate": "*"
}
}
routes.js
module.exports = function(app){
app.get('*',function(req, res){
res.send('index.html');
});
}
server.js
var express = require("express");
var app = express();
var mongoose = require("mongoose");
var config = require('./config/config');
var swig = require('swig');
var cons = require('consolidate');
mongoose.connect(config.dburl);
app.use(express.static(__dirname + '/public'));
app.set('views', __dirname + '/public');
app.engine('html', cons.swig);
app.set('view engine', 'html');
require('./routes') (app);
app.listen(config.port);
console.log('MeriDawat running on port ' + config.port)
Following are the version numbers of installed node modules
angular#1.2.18
consolidate#0.10.0
express#4.4.3
mongoose#3.8.12
passport#0.2.0
swig#1.3.2
I would appreciate any help in troubleshooting this to help me move forward. Thanks in advance.
I think this is the offending line, in routes.js:
res.send('index.html');
res.send() just sends the contents of the file back in the HTTP response.
To render a template and send the rendered results back, you want res.render() instead:
res.render('index.html')

Resources