Render EJS - Node JS - node.js

I would like to update my view after an ajax call, rendering compiled ejs from the server.
These two previous questions seem to achieve this but I cannot update my view
Can't Render EJS Template on Client
How to generate content on ejs with jquery after ajax call to express server
So from what I understand I should compile my ejs file (partial) on the server.
fixtures.ejs
<% fixtures.forEach((fixture) => { %>
<h2><%= fixture.home_team %> vs <%= fixture.away_team %></h2>
<% }) %>
index.js
app.post('/league_fixtures', async function (req, res) {
try {
var league_name = req.body.league_name;
const fixtures = await leagueFixtures(league_name);
//compile view
fs.readFile('./views/fixtures.ejs', "utf-8", function(err, template) {
fixture_template = ejs.compile(template, { client: true });
var html = fixture_template({fixtures: fixtures});
console.log(html);
// This logs out my HTML with fixtures so I am almost there
// <h2>Club Africain vs Al-Faisaly Amman</h2>
// <h2>Al Nejmeh vs ASAC Concorde</h2>
});
res.json({fixtures: fixtures });
} catch (err) {
res.status(500).send({ error: 'Something failed!' })
}
});
Ajax
$("a.league-name").on("click", function (e) {
e.preventDefault();
var league_name = $(this).text().trim();
$.ajax({
url: '/league_fixtures',
type: 'POST',
dataType: "json",
data: { league_name: league_name },
success: function(fixtures){
// How do i get HTML from server into here ?
$('#panel_' + league_name).html(fixtures);
},
error: function(jqXHR, textStatus, err){
alert('text status '+textStatus+', err '+err)
}
})
});
});
I don't get any errors when I fire the ajax request but I also do not get any data or HTML updated in my div.
What am I doing wrong?

So I finally got a working solution:
index.js
app.post('/league_fixtures', async function (req, res) {
try {
const league_name = req.body.league_name;
const fixtures = await leagueFixtures(league_name);
const file = await readFile('./views/fixtures.ejs');
var fixture_template = ejs.compile(file, { client: true });
const html = fixture_template({fixtures: fixtures});
res.send({ html: html });
} catch (err) {
res.status(500).send({ error: 'Something failed!' })
}
});
ajax call
$.ajax({
url: '/league_fixtures',
type: 'POST',
dataType: "json",
cache: true,
data: { league_name: league_name },
success: function(fixtures){
var html = fixtures['html'];
$('#panel_' + league_name).html(html);
},
error: function(jqXHR, textStatus, err){
alert('text status '+textStatus+', err '+err)
}
})

Related

Why I can't get the correct value from api

I have tried to post data in postman and it returns a json object , the methods are working good .
I have a problem to get the value of attribut when the api respond with a json object .
the forma of json like this :
{
"success" : "true"
}
the api method :
router.post("/sickers/user/login/", (req, res) => {
var values = JSON.parse(req.body);
var pass = values.password;
var email = values.email;
//console.log(values);
if (pass !== null || pass !== "") {
try {
con.connect();
con.query("SELECT Password FROM `sickers` WHERE Email='" + email + "'", function(err, rows, field) {
if (err) {
console.log(err);
res.send("an error detected try later");
} else {
try {
if (pass == rows[0].Password) {
//trying to send correct message from here
res.send({ success: "true" });
console.log("yes")
} else {
console.log("no")
res.send({ success: "false" });
}
} catch {
console.log("no")
res.send({ success: "false" });
}
}
});
} catch (e) {
res.send("no data found");
console.log("obj not found");
}
}
con.end();
});
the post method from a react app is :
//submit values
async submithandler(e) {
e.preventDefault();
try{
await fetch('http://localhost:8000/api/sickers/user/login/',{
method:'post',
mode:'no-cors',
headers:{
'Accept':'application/json',
'Content-type': 'application/json'
},
body:JSON.stringify({
password:this.state.password,
email:this.state.email
})
})
.then(response=>{
this.setState({data:response})
alert(data.success);
})
}catch(e){
alert(e)
}
}
the data declaration in state : data:[]
the error is that the data is undefined .
when you do an api call using fetch request, it returns a promise that contains the response and that response is resolved by the first .then(). after resolving this first promise it returns another response and you need to resolve it with another .then()
Please check the working example below:
import React, {Component} from "react";
class FetchExample extends React.Component {
state = {
isLoading: false,
questions: [],
error: null
};
fetchQuestions = () => {
fetch(`https://opentdb.com/api.php?amount=10&difficulty=hard&type=boolean`,)
.then(response => {
if (response.status !== 200) {
console.log('There was a problem. Status Code: ' + response.status);
return;
}
response.json().then(data => {
console.log(data);
this.setState({
questions: data,
isLoading: false
})
});
}
)
.catch(function (error) {
console.log('Error: ', error);
this.setState({error, isLoading: false})
});
};
render() {
const {isLoading, questions, error} = this.state;
return (
<React.Fragment>
<h1>Random Question</h1>
<button onClick={this.fetchQuestions}>Click for calling API using fetch</button>
{error ? <p>{error.message}</p> : null}
{!isLoading && questions.results ? (
questions.results.map((questions, index) => { //something right here
//is erroring
const {question, category, type, difficulty} = questions;
return (
<div key={index}>
<p>Question: {question}</p>
<p>Question Type: {type}</p>
<p>Difficulty: {difficulty}</p>
<hr/>
</div>
);
})
) : isLoading ? (
<h3>Loading...</h3>
) : null}
</React.Fragment>
);
}
}
export default FetchExample;
there is two problems here at this example with both parts api and react app ,
the first thing I did is to understand cors and how it works in express and I found that I should do the following steps to the api :
run
npm install cors
second is to add
const cors =require('cors')
and then :
app.use(cors());
and last step is inside the router post I should add cors :
router.post('path',cors(),(req,res)....
about react app code it just need to remove module="no-cors"
and then it works .

NodeJS / Express res.download not sending file

Here is the server code:
router.get("/download", (req, res) => {
console.log("downloading file...");
const file = `${__dirname}/../downloads/dummy.txt`;
res.download(file);
});
and here is the client-side JQuery:
const downloadSoftware = () => {
$.ajax({
type: "GET",
url: "/download",
success: function(res) {
console.log("success");
},
error: function(res) {
console.log("error");
}
});
};
HTML:
<a id="downloadParser" onclick="downloadSoftware()">
Download Parser
</a>
My problem is when I click on the tag, nothing happens in my browser when a file should be downloading.
EDIT:
when I click the tag i get this in the console for NodeJS:
GET /download 304 1.751 ms - -

Upload client file to website through node

I'm trying to achieved the following:
Client has to fill a form and submit it to the node server
If client has a business card, snap a picture and it updates the form.
I have the API to translate image to json.
But I struggle to upload that image through node.
I created an html form with an input=file.
When input is changed, Ajax is called to upload that image.
On node, the request is received and basically transferred to that other website (camcard).
Json response should be sent back to client.
I just can't achieve that..
Any idea?
Here is some code. I do a post in 2 ways (regular and Ajax)
Html client:
<form method='POST' id="formCard"
enctype='multipart/form-data'>
<input type=file class="btn btn-outline-primary" name=upfile
size=20 id="cardSelector" onChange="changeFile()">
</form>
<form method='POST' action='/postCardPic'>
Please specify a JPG file<br>
<input type=file name=upfile size=20><br><br>
<input type=submit value='Upload'>
</form>
<script>
function changeFile() {
var formData = new FormData();
formData.append( 'file', $( '#cardSelector' )[0].files[0] );
$.ajax({
data: formData,
enctype: 'multipart/form-data',
processData: false,
contentType: false,
type: "POST",
url: "/postCardPic",
success: function (response) { // on success..
console.log(response); // update the DIV
},
complete: function (data) {
hideLoader();
}
});
}
</script>
On the server side:
App.use(bodyParser.urlencoded({
extended: false,
limit: '50mb',
parameterLimit:'50000'
}));
app.use(bodyParser.json({
extended: false,
limit: '50mb',
parameterLimit:'50000'
}));
app.post('/postCardPic', function(req, response) {
var urlCamCard='http://whatever.com'
// var form = new Form();
// form.parse(req, function(err, fields, files) {
// res.writeHead(200, {'content-type': 'text/plain'});
// res.write('received upload:\n\n');
// res.end(util.inspect({fields: fields, files: files}));
// });
// form.on('file', function(name,file) {
// //stream it to localhost:4000 with same name
// fs.createReadStream(file.path).pipe(request.post(urlCamCard))
// });
request.post({
url:urlCamCard, form:req.body}, function optionalCallback(err, httpResponse, body) {
if (err) {
return console.error('upload failed:', err);
}
console.log('Upload successful! Server responded with:', body);
});
response.end();
});
Log in both cases is the same:
Upload successful! Server responded with: ErrorCode: -1 ErrorMsg: Image data size not supported
I found the solution.
Here's is the code on the server side:
App.post("/postCardPic", function(req, res) {
try {
var form = new multiparty.Form();
form.parse(req, function(err, fields, files) {});
form.on("file", function(name, file) {
var formData = {
file: {
value: fs.createReadStream(file.path),
options: {
filename: file.originalFilename
}
}
};
request.post(
{
url: theurl,
formData: formData
},
function optionalCallback(err, httpResponse, body) {
if (err) {
return console.error("upload failed:", err);
}
res.end(body);
}
);
});
} catch (err) {
console, log(err);
res.end();
}

"ValidationError: Post validation failed: title: Path `title` is required" in Vue.js

I have two directories where vue, node exist. And I have the vue build file in the node folder.
I am currently processing requests from nodes in the vue. However, the event occurs but the data does not cross.
I have the following code, I sent form data via create, but the return data is empty. Also, in mongodb, title and content are require: true, so I get an error like the title.
Please help me.
node/routes/api
...
const Post = require('../db/post');
router.post('/new', (req, res) => {
const post = new Post({
title: req.body.title,
content: req.body.content
});
post.save((err) => {
if (err) {
console.error(err);
res.json({ result: 0 });
return;
}
res.json({ result: 1 });
});
});
...
vue/src/component/new
<template>
<div id="form-group">
name : <input v-model="post.title">
content : <input v-model="post.content">
<button v-on:click="new" >New</button>
</div>
</template>
<script>
export default {
data: function () {
return {
post: {}
}
},
methods: {
new: function (evt) {
this.$http.post('/api/post/new', {
post: this.post
})
.then((response) => {
if (response.data.result === 0) {
alert('Error')
}
if (response.data.result === 1) {
alert('Success')
this.$router.push('/')
}
})
.catch(function (error) {
alert('error')
})
}
}
}
</script>

Hapi handlebar template not displaying json object data

Hey guys I have this simple handler that reads a mysql table and returns the json obj to the route like so.
handler
var PostStore = {};
PostStore.getAllPosts = function(){
conn.query('SELECT * FROM posts',function(err, result){
if(err){
console.log(err);
}
console.log(JSON.parse(JSON.stringify(result)));
return JSON.parse(JSON.stringify(result));
});
}
module.exports = PostStore;
router
{
path: '/',
method: 'GET',
handler: function (request, reply) {
console.log(PostStore.getAllPosts);
reply.view('index', {
title: 'My home page',
posts: PostStore.getAllPosts
});
}
}
index.html
<h1>{{title}}</h1>
{{#each posts}}
<h1>{{this.title}}</h1>
{{/each}}
Here is what the console output looks like
[Function]
[ { id: 1,
title: 'Hello World',
body: 'My First Post on this cool Hapi Blog!',
date: null } ]
As you can see the sql result is parsed in to a JSON obj but not read from handlebars. Also note that the {{title}} is displaying "My home page" as expected.
Any help would be much appreciated! Thank you.
PostStore.getAllPosts is async, you need to render the view inside it's callback function.
PostStore.getAllPosts(function (err, posts) {
// render the view
});
The only way to render async method in view is to call this methods in a pre handler and assign the return value so you can render the returned data inside the view. See here in hapi's documents for further explanation http://hapijs.com/api#route-prerequisites.
In PostStore routines this code
PostStore.getAllPosts = function(callback){
conn.query('SELECT * FROM posts',function(err, result){
if(err){
return callback(err);
}
return callback(result);
});
}
Then in handlers code
const getPosts = function (request, reply) {
... // do something async to set posts
PostStore.getAllPosts(function(err, results) {
if (err) {
return reply('Error occurred')
}
reply(results);
};
};
server.route({
method: 'GET',
path: '/',
config: {
pre: [
{ method: getPosts, assign: 'posts' }
],
handler: function (request, reply) {
reply.view('index', {
title: 'My home page',
posts: request.pre.posts,
});
}
}
});

Resources