Im trying to find a way to allow user to click on the link only after a specific function has completed running. So here in my case I have ejs template where there are two links in parapgraphs. Clicking on the first one ("Run python") activates a script that takes some time to complete. Then only after it has finished (so the there is "finished" - which comes from the line: console.log('finished') printed on the console) the next link("See the table") would be clickable (or unhid or something like that).
<h1>Search for a movie</h1>
<form action="results" method="GET">
<input type="text" placeholder="search term" name="search">
<input type="submit">
</form>
<p> Run python </p>
<p> See the table </p>
Here is the app.js code
var express = require("express")
var app = express()
var request = require("request")
var PythonShell = require('python-shell');
app.set("view engine", "ejs")
app.engine('html', require('ejs').renderFile);
var thelist =[]
app.get("/", function(req, res){
res.render("search")
})
var jsondata = ""
app.get("/results", function(req, res){
var query = req.query.search
var url = "http://www.omdbapi.com/?s=" + query + "&type=series&apikey=thewdb"
request(url, function(error, response, body){
if(!error && response.statusCode == 200){
var data = JSON.parse(body)
res.render("results", {data: data})
}
})
})
app.get('/data', function(req, res) {
//viewname can include or omit the filename extension
res.render(__dirname + '/well.html');
});
app.get("/show/:id", function (req, res) {
var id = req.params.id;
thelist.push(id)
console.log(thelist);
res.redirect('/')
});
app.get("/run", function(req, res) {
var pyshell = new PythonShell('script2.py');
pyshell.send(JSON.stringify(thelist))
pyshell.on('message', function (message) {
// received a message sent from the Python script (a simple "print" statement)
jsondata += message
});
// end the input stream and allow the process to exit
pyshell.end(function (err) {
if (err){
throw err;
};
console.log('finished');
});
res.redirect('/')
thelist = []
});
app.listen(process.env.PORT, process.env.IP, function(){
console.log("Movie App has started!!!");
})
You could probably do it with ajax, as emil suggests in his answer,
but since you are using ejs template engine, why don't use it ?
(You just need to change the .html template file extension to .ejs).
Also, I think your best option here is to not use res.redirect.
It would be better to use res.render and pass a parameter to the view, set to false by default.
A basic example:
server.js
// ...
app.get("/", function (req, res) {
res.render("search", { active: false });
})
// ...
app.get("/run", function (req, res) {
// ...
pyshell.end(function (err) {
if (err) throw err;
console.log('finished');
res.render("search", { active: true });
});
});
search.ejs
<p>Run python</p>
<p>
<%if (active) { %>
See the table
<% } else { %>
See the table
<% } %>
</p>
Now the See the table link is only clickable if the python script is finish.
Summary
It should be done by using AJAX calls. Instead of using redirect in /run, you can make it return some JSON data which indicates success/error state of the job.
On click of Run python, it will run AJAX call instead of redirecting page to /.
on OnSuccess of AJAX call, you can enable see the table.
Code
HTML
<p><a id="run" href="/run"> Run python </a></p>
<p><a id="show-data" href="/data" style="pointer-events:none;"> See the table </a></p>
Frontend Javascript
$(function() {
$('#run').click(function(event) {
event.preventDefault();
$.get('/run', function() {
$('#show-data').css('pointer-events', 'all');
});
});
});
NodeJs
app.get("/run", function(req, res) {
...
// res.redirect('/');
res.json({ success: true });
});
U can prevent links by using prevent function Jquery
$("a").click(function() {
if (status == "1") {
return true;
} else {
return false;
e.preventDefault();
}
});
This is the function where I used to stop the user from navigating to other pages without running a function.
I Initialized a variable called status with value = 0
Then I incremented the variable once the function was success.
So if the status is 0 then the URL won't work, after finishing the function the status will be incremented to 1 and hence if the condition is true and it will return true statement. If not it will return false statement and it will be prevented using e.preventDefault()
Why don't you try socket.io?
Here is simplified code, but fully functional...
(Note: "msg" object is for example only, for further usage)
index.html
<!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>Title</title>
</head>
<body>
<h1>Search for a movie</h1>
<p> Run python </p>
<p><a id="table-data"> See the table </a></p>
<script src="/socket.io/socket.io.js"></script>
<script>
var msg = {
msg: "TestMsgSend",
iParam: 100,
sParam: "Test Param 1",
aParam: [1, 2, 3]
}
var socket = io();
socket.on("server:finished", function (msg) {
// msg = "TestMsgReceived", for further usage
console.log("\nId: " + socket.id + "\nmsg: " + msg.msg + "\niParam: " + msg.iParam + "\nsParam: " + msg.sParam + "\naParam: " + msg.aParam);
document.getElementById("table-data").setAttribute("href", "/data");
});
function runPython() {
socket.emit("client:run", msg);
}
</script>
</body>
</html>
app.js
var express = require("express");
var app = express();
var http = require("http").Server(app);
var io = require("socket.io")(http);
app.use("/", express.static(__dirname + "/"));
// ***************************************************************************
// ***************************************************************************
// ***** Your code
// ***************************************************************************
// ***************************************************************************
io.on("connection", function (socket) {
console.log("New connection with id: " + socket.id);
socket.on("client:run", function (msg) {
// msg = "TestMsgSend", for further usage
console.log("\nId: " + socket.id + "\nmsg: " + msg.msg + "\niParam: " + msg.iParam + "\nsParam: " + msg.sParam + "\naParam: " + msg.aParam);
// ***************************************************************************
// ***************************************************************************
// ***** Your code
// ***************************************************************************
// ***************************************************************************
msg.msg = "TestMsgReceived";
msg.iParam++;
msg.sParam = "Test Param 2";
msg.aParam.push(4, 5, 6)
io.emit("server:finished", msg);
});
});
// ***************************************************************************
// ***************************************************************************
// ***** Your code
// ***************************************************************************
// ***************************************************************************
http.listen(80, function () {
console.log("listening on *:80");
});
package.json
{
"name": "test",
"version": "1.0.0",
"description": "",
"main": "app.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"express": "^4.16.2",
"socket.io": "^2.0.4"
}
}
Start with node app.js and enjoy
Why not something like a simple guard variable? In your code:
var ready = false; // 1) the guard
app.get('/data', function(req, res) {
if (ready) { // 2) view execution blocked until guard is ready
res.render(__dirname + '/well.html');
}
});
app.get("/run", function(req, res) {
var pyshell = new PythonShell('script2.py');
pyshell.send(JSON.stringify(thelist))
pyshell.on('message', function (message) {
// received a message sent from the Python script (a simple "print" statement)
jsondata += message
});
// end the input stream and allow the process to exit
pyshell.end(function (err) {
if (err) {
throw err;
};
ready = true; // 3) if evetything is OK the guard is now ready
console.log('finished');
});
res.redirect('/')
thelist = []
});
Related
I am trying to build a web app that allows a user to press a button and translate a piece of text using the Bing translator api. I try to run a translator.js file through a script tag but I of course cannot run this node.js code through the client html page. What would be the proper way to design this app. Is my only choice to use something such as requirejs? I also have an app.js file built using express from which I run the app. Sorry for posting a lot of code, I want to give people an idea of the structure of my app. My experience is limited so I am feeling somewhat lost as to how to approach the design of this portion of the app. I don't expect anyone to write the code for me, but to just point in a direction of techniques that I could research so that I could build this properly.
Here is my Node.js translation request called translator.js
const request = require('request');
const uuidv4 = require('uuid/v4');
var key_var = 'TRANSLATOR_TEXT_SUBSCRIPTION_KEY';
if (!process.env[key_var]) {
throw new Error('Please set/export the following environment variable: ' + key_var);
}
var subscriptionKey = process.env[key_var];
var endpoint_var = 'TRANSLATOR_TEXT_ENDPOINT';
if (!process.env[endpoint_var]) {
throw new Error('Please set/export the following environment variable: ' + endpoint_var);
}
var endpoint = process.env[endpoint_var];
let options = {
method: 'POST',
baseUrl: endpoint,
url: 'translate',
qs: {
'api-version': '3.0',
'to': ['en']
},
headers: {
'Ocp-Apim-Subscription-Key': subscriptionKey,
'Content-type': 'application/json',
'X-ClientTraceId': uuidv4().toString()
},
body: [{
'text': 'hallo welt'
}],
json: true,
};
function displayBingTranslate() {
request(options, function(err, res, body){
document.querySelector("#bingTranslateOutput") = JSON.stringify(body, null, 4);
});
};
var accessBingTranslate = document.getElementById("accessBingTranslateButton");
accessBingTranslate.addEventListener("click", function() {
displayBingTranslate();
});
And here is my html
<!-- Section to view online translation -->
<div class="container">
<div class="row">
<div class="col-lg-12 p-0">
<button
class="btn btn-outline-dark btn-sm mb-1"
id = "accessBingTranslateButton">Translate Flashcard</button>
<div class="row m-0 p-0">
<div id="bingTranslateOutput" class="col-lg-12 m-0">
</div>
<script>
// Overall list of flashcards.
var flashcardList = {
flashcards: [],
// Adds a flashcard object to Flashcard array.
addFlashcard: function(fcTextQuestion, fcTextTranslated) {
this.flashcards.push({
fcTextQuestion: fcTextQuestion,
fcTextTranslated: fcTextTranslated
});
},
};
// Add flashcards on load.
var flashcardsDB = <%- JSON.stringify(flashcardsDB) %>;
console.log("the DB:", flashcardsDB);
flashcardsDB.forEach(function(fcardDbToAdd){
flashcardList.addFlashcard(fcardDbToAdd.question, fcardDbToAdd.translation);
});
document.querySelector("#displayFlashcardTotal").textContent = flashcardList.flashcards.length;
console.log("the rest:",flashcardList.flashcards);
var currentFlashcard = 0;
</script>
<script src="/scripts/translator.js"></script>
</body>
</html>
and here is my app.js
var express = require("express");
var app = express();
var bodyParser = require("body-parser");
var mongoose = require("mongoose");
var methodOverride = require("method-override");
// Fix mongoose deprecations
mongoose.set('useNewUrlParser', true);
mongoose.set('useFindAndModify', false);
mongoose.set('useCreateIndex', true);
mongoose.set('useUnifiedTopology', true);
// Connect to database.
var url = "///////";
mongoose.connect(url, {
useNewUrlParser: true,
useCreateIndex: true,
}).then(() => {
console.log("connected to mongoDB");
}).catch(err => {
console.log("Error:", err.message);
});
app.use(bodyParser.urlencoded({extended: true}));
app.use(express.static(__dirname + '/public'));
// Set 'views' directory for any views
// being rendered res.render()
app.set("view engine", "ejs");
// Override HTTP verbs if necessary.
app.use(methodOverride("_method"));
var flashcardSchema = new mongoose.Schema ({
question: String,
translation: String
});
//creates model with above schema and has methods such as .find etc.
var Flashcard = mongoose.model("Flashcard", flashcardSchema);
app.get('/', (req, res) => {
Flashcard.find({}, function(err, allFlashcards){
if(err){
console.log(err);
} else {
res.render("home", {flashcardsDB: allFlashcards});
}
});
});
// Post to an input action
app.post("/flashcards", function(req, res) {
var question = req.body.question;
var translation = req.body.translation;
var newFlashcard = {question: question, translation: translation};
console.log(newFlashcard);
Flashcard.create(newFlashcard, function(err, newlyCreated){
if(err){
console.log(err);
} else {
res.redirect("/flashcards");
}
});
});
// Show info.
app.get("/info",function (req, res) {
res.render("info");
});
// Show all flashcards
app.get("/flashcards", function(req, res){
Flashcard.find({}, function(err, allFlashcards){
if(err){
console.log(err);
} else {
res.render("flashcards", {flashcards: allFlashcards});
}
});
});
// Show form to create new campground
app.get("/new", function(req, res){
res.render("new");
});
// Edit flashcard
app.get("/flashcards/:id/edit", function(req, res){
Flashcard.findById(req.params.id, function(err, selectedFlashcard){
if(err){
req.flash("error", "Flashcard not found!");
} else {
res.render("edit", {flashcard: selectedFlashcard});
}
});
});
// Update flashcard
app.put("/flashcards/:id", function(req, res){
Flashcard.findByIdAndUpdate(req.params.id, req.body.flashcard, function(err, updatedFlashcard){
if(err){
res.redirect("/flashcards");
} else {
res.redirect("/flashcards");
}
});
});
// Destroy Flashcard
app.delete("/flashcards/:id", function(req, res){
Flashcard.findByIdAndRemove(req.params.id, function(err){
if(err){
res.redirect("back");
} else {
//req.flash("success", "flashcard deleted.");
res.redirect("/flashcards");
}
});
});
app.listen(3000, () => console.log("Flashcard app is listening"));
I think the best aproach would be to pass the translator.js to the node.js server. Create a route on express for translations, and through that route you will call the translator.js and return the result. Then, on your html page, instead of running the translator.js directly, send a request to your server passing the necessary data.
On your app.js, you can do a route like this:
const translator = require('path_to_translator');
app.get('/translation', translator);
And then on your translator.js, you can export a function that will receive the parameters you need and return the result:
const bingTranslate = (req, res) => {
// YOUR CODE HERE
}
module.exports = bingTranslate
And then on your html you will make the button send a request to your server instead of calling translator.js, so you can change the value of the #bingTranslateOutput button based on the response you will receive from the server.
I was making the TODO list web application.
This is the 'todo.html' code below :
<html>
<head>
<title>My TODO List</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" type="text/css" href="main.css">
<script>
$(document).ready(function() {
$("#submit").click(function() {
var bla = $('#item').val();
$("#todo").append("<li class='todoVal'>" + bla + "</li>");
});
// $(document).click(function(e) {
// if (e.target.className == 'todoVal') {
// var t = e.target.innerText
// $(e.target).remove();
// $("#completed").append("<li class='completedVal'>" + t + "</li>");
// }
// });
$(document).click(function(e) {
if (e.target.className == 'completedVal') {
$(e.target).remove();
}
});
jQuery.fn.single_double_click = function(single_click_callback, double_click_callback, timeout) {
return this.each(function() {
var clicks = 0,
self = this;
jQuery(this).click(function(event) {
clicks++;
if (clicks == 1) {
setTimeout(function() {
if (clicks == 1) {
single_click_callback.call(self, event);
} else {
double_click_callback.call(self, event);
}
clicks = 0;
}, timeout || 500);
}
});
});
}
$(document).single_double_click(function(e) {
if (e.target.className == 'todoVal') {
var t = e.target.innerText
$(e.target).remove();
$("#completed").append("<li class='completedVal'>" + t + "</li>");
}
}, function(e) {
if (e.target.className == 'todoVal') {
$(e.target).remove();
}
});
$("#clear").click(function() {
$("li").remove();
});
});
</script>
</head>
<body>
<div id="addItem" class="box">
Task:
<input id="item" type="text" name="add_item" />
<button id="submit" type="button">Add</button>
<button id="clear" type="button">Clear All</button>
</div>
<div id="todo" class="box">
<h4>TODO:</h4>
<ul></ul>
</div>
<div id="completed" class="box">
<h4>Completed:</h4>
<ul></ul>
</div>
</body>
</html>
And this is the 'app.js' file below :
var express = require('express');
var app = express();
var cors = require('cors');
var bodyParser = require("body-parser");
// middleware
app.use(cors());
app.use(bodyParser.json());
var tasks = [];
// This will serve the HTML page todo.html
app.get('/', function(req, res) {
res.sendFile('todo.html', {
root: __dirname
});
});
// GET all tasks
app.get('/tasks', function(req, res) {
res.set('Content-Type', 'application/json')
res.status(200).send(tasks);
});
// POST to add a task
app.post('/task', function(req, res) {
res.set('Content-Type', 'application/json')
/* HELP ME HERE */
// returns 201 on success
res.status(201);
});
// DELETE a task
app.delete('/task', function(req, res) {
/* HELP ME HERE */
// returns 204 on success
res.status(204);
});
// DELETE all tasks
app.delete('/tasks', function(req, res) {
/* HELP ME HERE */
// returns 204 on success
res.status(204);
});
//
// Listen for HTTP requests on port 3000
app.listen(3000, function() {
console.log("listening on port 3000");
});
I want to pass the text box value to the JSON filter by 'TODO' and 'COMPLETED'.
If I add a new TODO list, it goes to the JSON and if the value goes to COMPLETED, it also goes to the JSON
This is the sample JSON result I want:
{"TODO" : [ "Go to market", "Eat dinner with Daniel"], "COMPLETED" : [ "Wash dishes", "Go to gym and Workout" ]}
This is just an example so you guys can just change the format.
Feel free to give me feedback from everything it's always welcome. btw I just started studying how to code
Thank you for spending time on this even if you didn't help me and have a great day!
What you have to do is simply make an Ajax Call to Nodejs APIs. For example,to '/task' and pass the input field value as params in json format then simply fetch them on in Nodejs as req.params.yourjsonKeys.
var inputData = $("#items").val();
$.ajax({
url: "/tasks",
type: "POST",
data: {params: inputData},
dataType: "html",
success: function(data){
if(data.code === 200){ // the response key 'code' from Nodejs
alert('Success');
}
}
});
Next, once you have the params, all you have to do is write it into your file using file system like so:
Create a javascript object with the table array in it
var obj = {
table: []
};
Add some data to it like
obj.table.push({id: req.params.id , square: req.params.square});
Convert it from an object to string with stringify
var json = JSON.stringify(obj);
//use fs to write the file to disk
var fs = require('fs');
fs.writeFile('myjsonfile.json', json, 'utf8', callback);
if you want to append it read the json file and convert it back to an object
fs.readFile('myjsonfile.json', 'utf8', function readFileCallback(err, data){
if (err){
console.log(err);
} else {
obj = JSON.parse(data); //now it an object
obj.table.push({id: 2, square:3}); //add some data
json = JSON.stringify(obj); //convert it back to json
fs.writeFile('myjsonfile.json', json, 'utf8', callback); // write it back
}});
Complete Code:
// POST to add a task
app.post('/task', function(req, res) {
res.set('Content-Type', 'application/json')
var obj = {
table: []
};
obj.table.push({id: req.params.id , square: req.params.square});
var json = JSON.stringify(obj);
var fs = require('fs');
fs.writeFile('myjsonfile.json', json, 'utf8', callback)
fs.readFile('myjsonfile.json', 'utf8', function readFileCallback(err, data){
if (err){
console.log(err);
} else {
obj = JSON.parse(data); //now it an object
obj.table.push({id: 2, square:3}); //add some data
json = JSON.stringify(obj); //convert it back to json
fs.writeFile('myjsonfile.json', json, 'utf8', callback); // write it back
// returns 201 on success
res.json({
code: 201,
message: 'Success'
});
}});
});
I am trying to use imap to search emails in my gmail inbox. It is going to be server side mail parser. To do so, I used express and I want to receive the input of users (from search field) using express. However, all the solutions I searched in the internet use app.post and bring me to a new page. I don't want to show any thing new in user interface. I just want to receive the input of user and give it to a function which performs imap.search. Any help? Here is the code:
index.htm
<!doctype html>
<html>
<body>
<form action="http://127.0.0.1:8081/process_post" method="POST">
Search: <input type = "text" name = "Search_value"> <br>
<input type = "submit" value = "SEARCH">
</form>
</body>
</html>
test.js
var express = require('express')
var bodyParser = require('body-parser');
var app = express()
app.use(express.static('public'));
// use body parser to easy fetch post body
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json())
var Imap = require('imap'),
inspect = require('util').inspect,
MailParser = require("mailparser").MailParser;
var imap = new Imap({
user: '***#gmail.com',
password: '*****',
host: 'imap.gmail.com',
port: 993,
tls: true
});
var fs = require('fs'), fileStream;
function openInbox(cb) {
imap.openBox('INBOX', true, cb);
}
// route to '/index.htm' to return the html file
app.get('/index.htm', function (req, res) {
res.sendfile('index.htm');
});
//route that receives the post body and returns your computation
app.post('/process_post', function (req, res) {
passtoserver(req.body, res);
});
app.listen(8081);
function passtoserver(parms, res) {
//get the parameters based on input name attribute from the html
//and parse strings to numbers
var m = parms.Search_value;
// res.writeHead(200, { 'Content-Type': 'text/html' });
res.end();
openInbox(function(err, box) {
if (err) throw err;
imap.search([ 'ALL', ['FROM', m] ], function(err, results) {
var f = imap.fetch(results, {
bodies: 'HEADER.FIELDS (FROM TO SUBJECT DATE)',
struct: true
});
f.on('message', function(msg, seqno) {
console.log('Message #%d', seqno);
var prefix = '(#' + seqno + ') ';
msg.on('body', function(stream, info) {
var buffer = '';
stream.on('data', function(chunk) {
buffer += chunk.toString('utf8');
});
stream.once('end', function() {
console.log(prefix + 'Parsed header: %s', inspect(Imap.parseHeader(buffer)));
});
});
msg.once('attributes', function(attrs) {
console.log(prefix + 'Attributes: %s', inspect(attrs, false, 8));
});
msg.once('end', function() {
console.log(prefix + 'Finished');
});
});
f.once('error', function(err) {
console.log('Fetch error: ' + err);
});
f.once('end', function() {
console.log('Done fetching all messages!');
});
});
});
}
imap.connect();
After submiting the user input, a new rout called process-post will ope. How to avoid this?
You can try it with:
https.request() API?
http.request() for secure protocal
The Code works fine with the uncomment lines.
But when i activate the else Statement i get every times the 'not found' even there is a match between req.params.code and data.airports[i].code.
var express = require('express');
var data = require('./data.json');
var app = express();
app.use(express.static('public'));
app.set('view engine', 'jade');
app.get('/', function (req, res) {
res.render('index', { title: 'Startseite', message: 'index.html'});
});
app.get('/de-de/code/:code', function (req, res) {
for (var i in data.airports) {
if (req.params.code == data.airports[i].code) {
res.render('iata-code', data.airports[i]);
/* } else {
res.send('not found'); */
};
};
});
app.listen(80, function () {
console.log('Example app is running!');
});
Edit:
I change the code to:
app.get('/de-de/code/:code', function (req, res) {
for (var i in data.airports) {
if (req.params.code === data.airports[i].code) {
res.status(200).render('iata-code', data.airports[i]);
} else {
res.status(404).send({ error: 'Something failed!' });
};
};
});
even i send the http status code 404 before the headers i get the error in my console: Error: Can't set headers after they are sent.
Edit2:
app.get('/de-de/code/:code', function (req, res) {
for (var i in data.airports) {
if (req.params.code === data.airports[i].code) {
res.writeHead(200, { "Content-Type": "text/html" });
res.render('iata-code', data.airports[i]);
} else {
res.writeHead(404, { "Content-Type": "text/html" });
res.write('Something failed!');
res.end();
};
};
});
Edit3: I set up an alternative way. But this is also not working. I am New to node.js but i still dind't find a solution.
var express = require('express');
var data = require('./data.json');
var airports = data.airports;
var app = express();
function filterData (reqCode) {
var result = {};
for (var i in airports) {
console.log('-----');
console.log(i + ': ' + reqCode + ' <--> ' + airports[i].code);
console.log('-----');
if (airports[i].code === reqCode) {
result = airports[i];
} else {
result = {};
};
};
return result;
console.log(result);
};
app.get('/de-de/:code', function (req, res, next) {
var reqCode = req.params.code;
if (filterData(reqCode) === {}) next('route');
else next();
}, function (req, res, next) {
res.write('200');
res.end();
});
app.get('/de-de/:code', function (req, res, next) {
res.write('404');
res.end();
});
app.listen(80, function () {
console.log('Example app is running! Cancel Server with CTRL + C');
});
Your else is inside the for loop, so whenever req.params.code == data.airports[0].code doesn't return true (first pass), it will return not found, instead of going through the next candidate.
You are sending response more than one that's why you are getting this issue.
Instead of res.send() you should use res.write() to send multiple responses.
res.send() sends entire HTTP response to the client includes headers and content even it ends the response.
And after that, you can't send anything.
Note:
After completing loop you can finally call the res.send() if it requires for you.
I have two major js files, one on the server side which is the server.js and another on the client side, which is enterchat.js. These two files are the ones which will communicate via socket.io. All socket events are working as expected.
server.js
var express = require('express'),
...
server = require('http').createServer(app),
io = require('socket.io').listen(server);
var usernames = [],
username_sockets = [];
...
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use('/', express.static(__dirname+'/public/'));
app.get('/chat', function (req, res) {
res.render('checkUsername', {title:'Socket IO Chat'});
});
app.get('/chatwindow', function (req, res) {
res.render('chatwindow', {title:'Welcome to chat window'});
});
io.sockets.on('connection', function (socket) {
socket.on('disconnect', function () {
...
delete username_sockets[socket.id];
console.log("Disconnected from " + user);
});
socket.on('newusr', function (newusrname) {
console.log("New user name request:: " + newusrname);
if(usernames.indexOf(newusrname) >= 0)
{
console.log("Already used username..");
socket.emit('usernameTaken', newusrname);
}
else
{
socket.emit('usernameavlbl', newusrname);
}
});
socket.on('startchat', function (usernameAvailable) {
if(usernames.indexOf(usernameAvailable) >= 0)
{
console.log("Just taken username..");
socket.emit('usernameJustTaken', usernameAvailable); //returning the username that was just taken
}
else
{
usernames.push(usernameAvailable);
console.log("Opening chat window for "+usernameAvailable);
username_sockets[socket.id] = usernameAvailable;
// trying to render jade view to open chatwindow on socket event
}
});
socket.on('sndmsg', function (message) {
socket.broadcast.emit('msgreceive', message, username_sockets[socket.id]);
});
socket.on('typing', function (username) {
socket.broadcast.emit('usertyping', username);
});
socket.on('stoppedtyping', function (username) {
socket.broadcast.emit('userstoppedtyping', username);
});
});
server.listen(8080,'0.0.0.0');
console.log("Listening on 8080..");
enterchat.js
var socket, usernameAvailable;
$(document).ready(function () {
connect();
...
...
$('#checkBtn').on('click', function(event) {
if($('#username').val() == '')
alert("Choose a username");
else
{
var newusrname = $('#username').val();
socket.emit('newusr', newusrname);
}
});
...
socket.on('usernameTaken', function (message) {
alert(message + " is already taken. Try another one..");
});
socket.on('usernameJustTaken', function (message) {
alert(message + " was just taken. Try another one..");
});
socket.on('usernameavlbl', function (newusrname) {
$('#chataway').attr('disabled', false);
usernameAvailable = newusrname;
});
$('#chataway').on('click', function () {
socket.emit('startchat', usernameAvailable);
});
});
function connect () {
socket = io.connect(null);
}
My question: How do I render the chatwindow view upon the socket event startchat?
I looked at this question: In Express.js, how can I render a Jade partial-view without a "response" object?, but I am not sure as to how to add it in my code so that a fresh jade view (chatwindow) is loaded on the browser.
You can use compileFile method of jade api, get the html and then emit a socket event containing the html data. You can append that html to the DOM.
socket.on('startchat', function (usernameAvailable) {
if(usernames.indexOf(usernameAvailable) >= 0)
{
console.log("Just taken username..");
socket.emit('usernameJustTaken', usernameAvailable); //returning the username that was just taken
}
else
{
usernames.push(usernameAvailable);
console.log("Opening chat window for "+usernameAvailable);
username_sockets[socket.id] = usernameAvailable;
var fn = jade.compileFile('path to jade file', options);
// Render function
var html = fn();
// Now you can send this html to the client by emitting a socket event
}
});