Upload stream to Dropbox session upload - node.js

I have a form that accepts a file to pass on to Dropbox using the session upload. I've wrapped the code in a Fastify server but always end up with an error in append:
{"error_summary": "closed/..", "error": {".tag": "closed"}}.
Here's the Fastify server:
require("dotenv").config()
const https = require("https")
const JSONbig = require("json-bigint")
const TOKEN = process.env.DROPBOX_ACCESS_TOKEN
const fastify = require("fastify")({
logger: {
level: "info"
}
})
fastify.addContentTypeParser("*", function (req, done) {
done()
})
// Promisify https request
const httpRequest = (url, options, data) => {
return new Promise((resolve, reject) => {
const req = https.request(url, options, (res) => {
let body = ""
res.on("data", (chunk) => {
console.log("SDSDSDSDASDASDSAD")
body += chunk.toString()
})
res.on("error", reject)
res.on("end", () => {
if (res.statusCode >= 200 && res.statusCode <= 299) {
resolve({ statusCode: res.statusCode, headers: res.headers, body: JSON.parse(body) })
} else {
reject("Request failed. status: " + res.statusCode + ", body: " + body)
}
})
})
req.on("error", reject)
if (data) req.write(data)
req.end()
})
}
fastify.register(require("fastify-cors"))
fastify.post("/", async (req, reply) => {
const stream = req.raw
const initResponse = await httpRequest(
"https://content.dropboxapi.com/2/files/upload_session/start",
{
method: "post",
headers: {
Authorization: `Bearer ${TOKEN}`,
"Dropbox-API-Arg": JSON.stringify({
close: false
}),
"Content-Type": "application/octet-stream"
}
}
)
const sessionId = initResponse.body.session_id
req.log.info(`Initiating session ${sessionId}`)
let offset = 0
stream.on("data", async (chunk) => {
req.log.info("Sending chunk")
stream.pause()
const appendResponse = await httpRequest(
`https://content.dropboxapi.com/2/files/upload_session/append_v2`,
{
method: "post",
headers: {
Authorization: `Bearer ${TOKEN}`,
"Dropbox-API-Arg": JSONbig.stringify({
cursor: {
session_id: sessionId,
offset
},
close: false
}),
"Content-Type": "application/octet-stream"
}
},
chunk
)
stream.resume()
offset += chunk.length
})
stream.on("end", async () => {
const terminateResponse = await httpRequest(
`https://content.dropboxapi.com/2/files/upload_session/finish`,
{
method: "post",
headers: {
Authorization: `Bearer ${TOKEN}`,
"Dropbox-API-Arg": JSONbig.stringify({
cursor: {
session_id: sessionId,
offset: offset
},
commit: {
path: "/Upload/test-large.txt",
mode: "add",
autorename: true,
mute: false,
strict_conflict: false
}
}),
"Content-Type": "application/octet-stream"
}
}
)
req.log.info("upload session finished")
reply.code(204).send()
})
})
fastify.listen(3000, (err) => {
if (err) {
fastify.log.fatal(err)
process.exit(1)
}
console.log(`server listening on ${fastify.server.address().port}`)
})
And here's the form:
<!DOCTYPE html>
<!-- Coding By CodingNepal - youtube.com/codingnepal -->
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>File Upload with Progress Bar | CodingNepal</title>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css"
/>
<style>
/* Import Google font - Poppins */
#import url("https://fonts.googleapis.com/css2?family=Poppins:wght#400;500;600&display=swap");
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: "Poppins", sans-serif;
}
body {
display: flex;
align-items: center;
justify-content: center;
min-height: 100vh;
background: #6990f2;
}
::selection {
color: #fff;
background: #6990f2;
}
.wrapper {
width: 430px;
background: #fff;
border-radius: 5px;
padding: 30px;
box-shadow: 7px 7px 12px rgba(0, 0, 0, 0.05);
}
.wrapper header {
color: #6990f2;
font-size: 27px;
font-weight: 600;
text-align: center;
}
.wrapper form {
height: 167px;
display: flex;
cursor: pointer;
margin: 30px 0;
align-items: center;
justify-content: center;
flex-direction: column;
border-radius: 5px;
border: 2px dashed #6990f2;
}
form :where(i, p) {
color: #6990f2;
}
form i {
font-size: 50px;
}
form p {
margin-top: 15px;
font-size: 16px;
}
section .row {
margin-bottom: 10px;
background: #e9f0ff;
list-style: none;
padding: 15px 20px;
border-radius: 5px;
display: flex;
align-items: center;
justify-content: space-between;
}
section .row i {
color: #6990f2;
font-size: 30px;
}
section .details span {
font-size: 14px;
}
.progress-area .row .content {
width: 100%;
margin-left: 15px;
}
.progress-area .details {
display: flex;
align-items: center;
margin-bottom: 7px;
justify-content: space-between;
}
.progress-area .content .progress-bar {
height: 6px;
width: 100%;
margin-bottom: 4px;
background: #fff;
border-radius: 30px;
}
.content .progress-bar .progress {
height: 100%;
width: 0%;
background: #6990f2;
border-radius: inherit;
}
.uploaded-area {
max-height: 232px;
overflow-y: scroll;
}
.uploaded-area.onprogress {
max-height: 150px;
}
.uploaded-area::-webkit-scrollbar {
width: 0px;
}
.uploaded-area .row .content {
display: flex;
align-items: center;
}
.uploaded-area .row .details {
display: flex;
margin-left: 15px;
flex-direction: column;
}
.uploaded-area .row .details .size {
color: #404040;
font-size: 11px;
}
.uploaded-area i.fa-check {
font-size: 16px;
}
</style>
</head>
<body>
<div class="wrapper">
<header>File Uploader JavaScript</header>
<form action="#">
<input class="file-input" type="file" name="file" hidden />
<i class="fas fa-cloud-upload-alt"></i>
<p>Browse File to Upload</p>
</form>
<section class="progress-area"></section>
<section class="uploaded-area"></section>
</div>
<script>
const form = document.querySelector("form"),
fileInput = document.querySelector(".file-input"),
progressArea = document.querySelector(".progress-area"),
uploadedArea = document.querySelector(".uploaded-area")
// form click event
form.addEventListener("click", () => {
fileInput.click()
})
fileInput.onchange = ({ target }) => {
let file = target.files[0] //getting file [0] this means if user has selected multiple files then get first one only
if (file) {
let fileName = file.name //getting file name
if (fileName.length >= 12) {
//if file name length is greater than 12 then split it and add ...
let splitName = fileName.split(".")
fileName = splitName[0].substring(0, 13) + "... ." + splitName[1]
}
uploadFile(fileName) //calling uploadFile with passing file name as an argument
}
}
// file upload function
function uploadFile(name) {
let xhr = new XMLHttpRequest() //creating new xhr object (AJAX)
xhr.open("POST", "http://localhost:3000") //sending post request to the specified URL
xhr.upload.addEventListener("progress", ({ loaded, total }) => {
//file uploading progress event
let fileLoaded = Math.floor((loaded / total) * 100) //getting percentage of loaded file size
let fileTotal = Math.floor(total / 1000) //gettting total file size in KB from bytes
let fileSize
// if file size is less than 1024 then add only KB else convert this KB into MB
fileTotal < 1024
? (fileSize = fileTotal + " KB")
: (fileSize = (loaded / (1024 * 1024)).toFixed(2) + " MB")
let progressHTML = `<li class="row">
<i class="fas fa-file-alt"></i>
<div class="content">
<div class="details">
<span class="name">${name} • Uploading</span>
<span class="percent">${fileLoaded}%</span>
</div>
<div class="progress-bar">
<div class="progress" style="width: ${fileLoaded}%"></div>
</div>
</div>
</li>`
// uploadedArea.innerHTML = ""; //uncomment this line if you don't want to show upload history
uploadedArea.classList.add("onprogress")
progressArea.innerHTML = progressHTML
if (loaded == total) {
progressArea.innerHTML = ""
let uploadedHTML = `<li class="row">
<div class="content upload">
<i class="fas fa-file-alt"></i>
<div class="details">
<span class="name">${name} • Uploaded</span>
<span class="size">${fileSize}</span>
</div>
</div>
<i class="fas fa-check"></i>
</li>`
uploadedArea.classList.remove("onprogress")
// uploadedArea.innerHTML = uploadedHTML; //uncomment this line if you don't want to show upload history
uploadedArea.insertAdjacentHTML("afterbegin", uploadedHTML) //remove this line if you don't want to show upload history
}
})
let data = new FormData(form) //FormData is an object to easily send form data
xhr.send(data) //sending form data
}
</script>
</body>
</html>
Does need an app created on DB to get oauth token to run example.
Anyone see the issue here? I've worked from a number of examples online but all of them assume I am using some dummy static file rather than incoming uploaded file.

Ok figured it out. Basically in my example I am terminating the session on end but it turns out the end event is fired at the same time as the last data event so I am effectively closing the session in the midst of the last chunk append. I refactored things to have a flag isEnd that gets set in the end event handler and moved the terminate session and resolve code inside of the data handler to be fired from there once isEnd is set.

Related

Express jwt is undefiend

So, i am making this request from my frontend to get all conversations of a user.
When the request made to the node server, it checks for "express-jwt" and says access denied.
When i console.log the jwt, it shows that the jwt is undefiend
(i think the bearer is ok, since it shows in the req.headers.authorization)
My react code:
import React, { useState, useEffect, useRef } from "react";
import styled from "styled-components";
import apiCalls from "../../backend/apiCalls";
import Conversion from "../../Components/Shared/Conversion";
import Message from "../../Components/Shared/Message";
import ToastSuccess from "../../Components/Shared/ToastSuccess";
import Toast from "../../Components/Shared/ToastSuccess";
import { io } from "socket.io-client";
function ChiefNotification({ id }) {
const [list, setList] = useState([]);
const socket = useRef();
useEffect(() => {
socket.current = io("ws://localhost:8900");
socket.current.on("getMessage", (data) => {
setRecievedMessages({
sender: data.senderId,
text: data.text,
createdAt: Date.now(),
});
});
}, []);
const [showConversations, setShowConversations] = useState([]);
const [conversations, setConversations] = useState([]);
const [currentChat, setCurrentChat] = useState(null);
const [messages, setMessages] = useState([]);
const [newMessage, setNewMessage] = useState("");
const [recievedMessages, setRecievedMessages] = useState("");
const scrollRef = useRef();
useEffect(() => {
recievedMessages &&
currentChat?.members.includes(recievedMessages.sender) &&
setMessages((prev) => [...prev, recievedMessages]);
}, [recievedMessages, currentChat]);
const getConversation = async () => {
await apiCalls
.getConversation(id)
.then((data) => {
setConversations(data?.data);
setShowConversations(data?.data);
})
.catch((err) => {
Toast.ToastFailure(err.response.data);
});
};
const handleSubmit = async (e) => {
e.preventDefault();
const message = {
sender: id,
text: newMessage,
conversationId: currentChat._id,
};
const recieverId = currentChat.members[1];
socket.current.emit("sendMessaage", {
senderId: id,
recieverId: recieverId,
text: newMessage,
});
await apiCalls
.sendMessage(message)
.then((data) => {
setMessages([...messages, data?.data]);
setNewMessage("");
})
.catch((err) => {
Toast.ToastFailure(err.response.data);
});
};
//handling sockets
const getSocketInfo = () => {
socket.current.emit("addUser", id);
socket.current.on("getUsers", (users) => {
console.log(users);
});
};
const getAllUsers = async () => {
await apiCalls
.getAllConvo()
.then((res) => {
setList(res?.data);
})
.catch((err) => {
ToastSuccess.ToastFailure(err?.response.data);
});
};
const NewConversation = (keyword) => {
if (keyword.length > 2) {
setShowConversations(
list.filter(
(listItem) =>
listItem.firstName.toLowerCase().includes(keyword.toLowerCase()) ||
listItem.lastName.toLowerCase().includes(keyword.toLowerCase())
)
);
} else {
setShowConversations(conversations);
}
};
useEffect(() => {
Promise.all([getConversation(), getSocketInfo(), getAllUsers()]);
}, []);
useEffect(() => {
const getMessages = async () => {
await apiCalls
.getMessages(currentChat?._id)
.then((data) => {
setMessages(data?.data);
})
.catch((err) => {
ToastSuccess.ToastFailure(err.response.data);
});
};
if (currentChat) getMessages();
}, [currentChat]);
useEffect(() => {
scrollRef.current?.scrollIntoView({ behavior: "smooth" });
}, [messages]);
return (
<>
<Breadcrum>Dashboard / Notifications</Breadcrum>
<Messenger>
<CheckMenu>
<CheckMenuWrapper>
<ChatMenuInp
placeholder="Search for Friends"
onChange={(e) => NewConversation(e.target.value)}
/>
{showConversations.map((c, index) => (
<div onClick={() => setCurrentChat(c)} key={index}>
<Conversion conversation={c} />
</div>
))}
</CheckMenuWrapper>
</CheckMenu>
<ChatBox>
<CheckBoxWrapper>
{currentChat ? (
<>
<CheckBoxTop>
{messages.map((m, index) => {
return (
<div ref={scrollRef} key={index}>
<Message message={m} own={m.sender === id} />
</div>
);
})}
</CheckBoxTop>
<CheckBoxBottom>
<ChatMessageArea
placeholder="write something...."
onChange={(e) => setNewMessage(e.target.value)}
value={newMessage}
/>
<ChatSendButton onClick={handleSubmit}>Send</ChatSendButton>
</CheckBoxBottom>
</>
) : (
<NoConversation>Open a Conversation to Start Chat</NoConversation>
)}
</CheckBoxWrapper>
</ChatBox>
</Messenger>
</>
);
}
export default ChiefNotification;
const Messenger = styled.div`
display: flex;
margin: 0% 5% 1% 5%;
border: 1px solid #e0e0e0;
border-radius: 5px;
max-height: 80vh;
min-height: 70vh;
`;
const CheckMenu = styled.div`
flex: 3;
`;
const CheckMenuWrapper = styled.div`
padding: 10px;
border-right: 1px solid #e0e0e0;
height: 100%;
`;
const ChatMenuInp = styled.input`
width: 90%;
padding: 10px;
border: none;
border-bottom: 1px solid #e0e0e0;
`;
const ChatMessageArea = styled.textarea`
width: 80%;
height: 90px;
padding: 10px;
`;
const CheckBoxBottom = styled.div`
margin-top: 5px;
display: flex;
align-items: center;
justify-content: space-between;
background-color: #f5f5f5;
padding: 2%;
`;
const ChatBox = styled.div`
flex: 7;
padding: 5px 15px;
`;
const CheckBoxWrapper = styled.div`
display: flex;
flex-direction: column;
justify-content: space-between;
position: relative;
height: 100%;
position: relative;
`;
const CheckBoxTop = styled.div`
height: 100%;
overflow-y: scroll;
padding-right: 10px;
`;
const ChatSendButton = styled.button`
width: 100px;
height: 40px;
border: none;
color: white;
border-radius: 1px;
background-color: #5f9ab4;
cursor: pointer;
`;
const Breadcrum = styled.h6`
color: #003951;
padding: 1% 5%;
display: flex;
`;
const NoConversation = styled.div`
position: absolute;
top: 10%;
font-size: 50px;
color: lightgray;
cursor: default;
width: 100%;
text-align: center;
`;
The Axios Setup Code:
import axios from "axios";
import { getCookie } from "../Auth/auth";
const authToken = getCookie("token");
axios.defaults.baseURL = "http://localhost:5000";
axios.defaults.headers.common["Authorization"] = `Bearer ${authToken}`;
axios.interceptors.response.use(null, (error) => {
const expectedError =
error.response &&
error.response.status >= 400 &&
error.response.status < 500;
if (!expectedError) {
console.log("Logging error", error);
alert("An unexpected Error occurred");
}
return Promise.reject(error);
});
// eslint-disable-next-line import/no-anonymous-default-export
export default {
get: axios.get,
post: axios.post,
put: axios.put,
delete: axios.delete,
};
The code for the API call and the jwt file
//get list of people that you can have conversation with
router.get("/allConversations", [chief], async (req, res) => {
const getUsers = await User.find({ accountStatus: true }).select(
"id firstName lastName"
);
if (getUsers) {
return res.status(200).json(getUsers);
} else return res.status(400).json("Error Occured while getting users");
});
The code for JWT
const expressJwt = require("express-jwt");
function authJwt() {
const secret = process.env.SECRET;
return expressJwt({
secret,
algorithms: ["HS256"],
isRevoked: isRevoked,
}).unless({
path: [
{ url: /\/issues(.*)/, methods: ["GET", "OPTIONS"] },
{ url: /\journal\/download(.*)/, methods: ["GET", "OPTIONS"] },
{ url: /\user\/activate(.*)/, methods: ["GET", "POST", "OPTIONS"] },
{
url: /\user\/auth\/password\/reset(.*)/,
methods: ["GET", "POST", "OPTIONS"],
},
{ url: /\/public\/uploads(.*)/, methods: ["GET", "OPTIONS"] },
{ url: /\/journal\/search(.*)/, methods: ["GET", "OPTIONS"] },
{ url: /\/journal\/currentIssues(.*)/, methods: ["GET", "OPTIONS"] },
{ url: /\journal/, methods: ["POST", "OPTIONS"] },
{ url: /\user\/chief(.*)/, methods: ["GET", "DELETE", "OPTIONS"] },
{ url: /\messages(.*)/, methods: ["GET", "OPTIONS"] },
"/user/login",
"/user/signup",
"/journal/latest",
"/user/forget",
"/user/reset",
"/user/chief/all",
],
});
}
async function isRevoked(req, payload, done) {
if (!payload.userType) {
done(null, true);
}
done();
}
module.exports = authJwt;

Display incoming messages in different html page

This is piece of code for small chat.
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
app.get('/', function(req, res){
res.sendFile(__dirname + '/index.html');
});
io.on('connection', function(socket){
socket.on('chat message', function(msg){
console.log('message: ' + msg);
});
});
http.listen(3000, function(){
console.log('listening on *:3000');
});
and html page:
<!doctype html>
<html>
<head>
<title>Socket.IO chat</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font: 13px Helvetica, Arial; }
form { background: #000; padding: 3px; position: fixed; bottom: 0; width: 100%; }
form input { border: 0; padding: 10px; width: 90%; margin-right: .5%; }
form button { width: 9%; background: rgb(130, 224, 255); border: none; padding: 10px; }
#messages { list-style-type: none; margin: 0; padding: 0; }
#messages li { padding: 5px 10px; }
#messages li:nth-child(odd) { background: #eee; }
</style>
</head>
<script src="/socket.io/socket.io.js"></script>
<script src="/socket.io/socket.io.js"></script>
<script src="https://code.jquery.com/jquery-1.11.1.js"></script>
<script>
$(function () {
var socket = io();
$('form').submit(function(){
socket.emit('chat message', $('#m').val());
$('#m').val('');
return false;
});
});
</script>
<body>
<ul id="messages"></ul>
<form action="">
<input id="m" autocomplete="off" /><button>Send</button>
</form>
</body>
</html>
on console window I see received messages from client but what i want to achieve is when i open http://localhost:3000/msgmonitor i would like to see all this messages that are comming from clients. How to do this?

Simple websocket tutorial app not recieving 'chat' events despite being connected

I am following along with a tutorial which demonstrates how to set up a very simple chat app with nodejs (express) and WebSockets. I can confirm that the connection between client and server is established but cannot figure out why the 'chat' event does not get processed by the server on the other side. I am using Socket.io 2.04 and my server is running out of Cloud9. I am just trying to get a working example set up so I have the CSS, HTML, and script in the same file for the webpage. Any idea what I am doing wrong? I've spent enough hours fiddling with this that I could really use some expert advice...
// server side code
var express =require("express");
var app = express();
var socket = require('socket.io');
var bodyParser = require("body-parser");
app.use(bodyParser.json());
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.use(express.static(__dirname + "/public"));
app.get("/websockets", function(req, res) {
res.render("websockets.ejs");
});
var server = app.listen(process.env.PORT, process.env.IP, function(){
console.log("SERVER IS RUNNING!");
});
// Socket setup
var io = socket(server);
io.on('connection', function(socket){
console.log('made socket connection', socket.id);
// Handle chat event
socket.on('chat', function(data){
console.log(data);
io.sockets.emit('chat', data);
});
});
and below is the page sent to the client
<html>
<head>
<meta charset="utf-8">
<title>WebSockets 101</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.0.4/socket.io.js"></script>
<style>
body{
font-family: 'Nunito';
}
h2{
font-size: 18px;
padding: 10px 20px;
color: #575ed8;
}
#mario-chat{
max-width: 600px;
margin: 30px auto;
border: 1px solid #ddd;
box-shadow: 1px 3px 5px rgba(0,0,0,0.05);
border-radius: 2px;
}
#chat-window{
height: 400px;
overflow: auto;
background: #f9f9f9;
}
#output p{
padding: 14px 0px;
margin: 0 20px;
border-bottom: 1px solid #e9e9e9;
color: #555;
}
#feedback p{
color: #aaa;
padding: 14px 0px;
margin: 0 20px;
}
#output strong{
color: #575ed8;
}
label{
box-sizing: border-box;
display: block;
padding: 10px 20px;
}
input{
padding: 10px 20px;
box-sizing: border-box;
background: #eee;
border: 0;
display: block;
width: 100%;
background: #fff;
border-bottom: 1px solid #eee;
font-family: Nunito;
font-size: 16px;
}
button{
background: #575ed8;
color: #fff;
font-size: 18px;
border: 0;
padding: 12px 0;
width: 100%;
border-radius: 0 0 2px 2px;
cursor: pointer;
}
</style>
</head>
<body>
<div id="mario-chat">
<div id="chat-window">
<div id="output"></div>
</div>
<input id="handle" type="text" placeholder="Handle"/>
<input id="message" type="text" placeholder="Message"/>
<button id="send">Send</button>
</div>
<script>
// Make connection
var socket = io.connect('https://mywebsitename:8080');
// Query DOM
var message = document.getElementById('message'),
handle = document.getElementById('handle'),
btn = document.getElementById('send'),
output = document.getElementById('output');
// Emit events
btn.addEventListener('click', function(){
socket.emit('chat', {
message: message.value,
handle: handle.value
});
message.value = "";
console.log("It should have sent out a chat event...");
});
// Listen for events
socket.on('chat', function(data){
output.innerHTML += '<p><strong>' + data.handle + ': </strong>' + data.message + '</p>';
});
</script>
</body>
</html>

Socket.io server doesn't receive messages

I'm trying to follow the official socket.io tutorial but I can't get the server to receive messages. I've spent a few hours trying all sorts of things. I'm completely out of ideas.
Here's the server:
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
app.get('/', function (req, res) {
res.sendFile(__dirname + '/index.html');
});
io.on('connection', function (socket) {
//socket.emit('greeting', 'welcome to the chat');
socket.on('chat', function (msg) {
console.log('message: ' + msg);
});
});
http.listen(3000, function () {
console.log('listening on *:3000');
});
and the client:
<!doctype html>
<html>
<head>
<title>Socket.IO chat</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font: 13px Helvetica, Arial;
}
form {
background: #000;
padding: 3px;
position: fixed;
bottom: 0;
width: 100%;
}
form input {
border: 0;
padding: 10px;
width: 90%;
margin-right: .5%;
}
form button {
width: 9%;
background: rgb(130, 224, 255);
border: none;
padding: 10px;
}
#messages {
list-style-type: none;
margin: 0;
padding: 0;
}
#messages li {
padding: 5px 10px;
}
#messages li:nth-child(odd) {
background: #eee;
}
</style>
<script src="/socket.io/socket.io.js"></script>
<script src="http://code.jquery.com/jquery-1.11.1.js"></script>
<script>
//localStorage.debug = '*';
var socket = io("http://localhost:3000/");
socket.on('greeting',
function (msg)
{
console.log(msg);
}
);
/*
$('form').submit(function ()
{
socket.emit('chat message', $('#m').val());
//$('#m').val('');
return false;
});
*/
$("#sendBtn").click(function ()
{
socket.emit('chat', $('#m').val());
return false;
});
</script>
</head>
<body>
<ul id="messages"></ul>
<form action="">
<input id="m" autocomplete="off" /><button id="sendBtn">Send</button>
</form>
</body>
</html>
The client can receive messages from the server but the other way around doesn't work. I've tried turning on debugging but I can't tell if what I'm seeing is right or wrong. However, there certainly is an interaction happening when I press send on the webpage.
Here's how it looks from the client side:
You need to correct the bind to your element, and you are trying to bind to a component that isn't rendered yet. You need to wait for DOM to be ready. Try this.
$(function() {
$("#sendBtn").on('click', function ()
{
socket.emit('chat', $('#m').val());
return false;
});
});
Wrapping your function like this you are telling to execute only when the page is loaded

Node.js with socket.io, capturing form data to display on page

What I am trying to do is basic, but cant get my data back to the page. I want to capture some usewr information in a form before I direct them to a chat screen, once directed to the chat screen I will use form data to append their name and question(from the form) to the chat window.
I have edited the original post, if I change the line return data in index.js to:*
io.emit('user capture', data)
*...and comment out the display none on the chat window.
I get the data posted to the chat window, now I just need to be able to hide the chat window... Any ideas?
Below is my index.html:
<!doctype html>
<html>
<head>
<title>Socket.IO chat</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font: 13px Helvetica, Arial; }
form[name="chat"] { background: #000; padding: 3px; position: fixed; bottom: 0; width: 100%; }
form[name="chat"] input { border: 0; padding: 10px; width: 90%; margin-right: .5%; }
form[name="chat"] button { width: 9%; background: rgb(130, 224, 255); border: none; padding: 10px; }
#messages { list-style-type: none; margin: 0; padding: 0; }
#messages li { padding: 5px 10px; }
#messages li:nth-child(odd) { background: #eee; }
/*.chat { display: none; }*/
</style>
</head>
<body>
<div class="pages">
<div class="user_capture">
<form name="user_capture" enctype='application/json'>
<button>Close</button><br/><br/>
<label for="username">Your Name: *</label><br/>
<input id="username" type="text" value="" name="username" autocomplete="off" required="required" /><br/>
<label for="email">Email: *</label><br/>
<input id="email" value="" name="email_address" autocomplete="off" /><br/>
<label for="phone">Phone:</label><br/>
<input id="phone" value="" name="phone" autocomplete="off" /><br/>
<label for="question">Question: </label><br/>
<textarea id="question" name="question">
</textarea required="required"><br/><br/>
<button>Chat</button>
</form>
</div>
<div class="chat">
<ul id="messages"></ul>
<form name="chat">
<input id="message" autocomplete="off" /><button>Send</button>
</form>
</div>
</div>
<script src="https://cdn.socket.io/socket.io-1.2.0.js"></script>
<script src="http://code.jquery.com/jquery-1.11.1.js"></script>
<script>
var socket = io();
$('form[name="user_capture"]').submit(function(){
var data = {
username:$('[name="username"]').val(),
question:$('[name="question"]').val()
}
socket.emit('user capture', data);
//return false;
});
socket.on('user capture', function(data){
$('form[name="user_capture"]').hide();
$('form[name="chat"]').show();
// $('#messages').append(data.username +' says: '+ data.question);
});
$('form[name="chat"]').submit(function(){
socket.emit('chat message', $('#message').val());
$('#message').val('');
return false;
});
socket.on('chat message', function(msg){
$('#messages').append($('<li>').text(msg));
});
</script>
</body>
</html>
Below is my index.js:
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var status = 'Disconnected';
app.get('', function(req, res){
res.sendFile(__dirname + '/index.html');
});
io.on('connection', function(socket){
var status = 'Connected';
socket.on('chat message', function(msg){
io.emit('chat message', msg);
io.emit('status', status);
});
socket.on('user capture', function(data){
io.emit('user capture', data);
});
});
http.listen(3000, function(){
console.log('listening on *:3000');
});
use following code
$('form[name="user_capture"]').click(function(e){
e.preventDefault();
var data = {
username:$('[name="username"]').val(),
question:$('[name="question"]').val()
}
So you guys were right the form was submitting refreshing the page and causing loss of data I also decided to not use a form at all.. Just inputs and tags as I am not using PHP so no need for POST. Below is my working code:
index.html
<!doctype html>
<html>
<head>
<title>Socket.IO chat</title>
<style>
* { box-sizing: border-box; }
body { margin: 0; padding: 0; font: 13px Helvetica, Arial; }
[data-close] { float: right; }
[data-status] { width: 100%; }
.chat { display: none; }
.chat .send-area { background: #000; padding: 15px; position: fixed; bottom: 0; width: 100%; }
.chat .send-arae input { border: 0; padding: 10px; width: 90%; margin-right: .5%; }
.chat [data-send] { float: right; text-align: center;width: 9%; background: rgb(130, 224, 255); border: none; padding: 10px; }
.chat .send-area #message { width: 90%; padding: 9px; }
#messages { width: 70%;float: left; list-style-type: none; margin: 0; padding: 0; }
#messages li { padding: 5px 10px; }
#messages li:nth-child(odd) { background: #eee; }
[data-online] { float: right; background: #d9d9d9; width: 30%; }
.clr { clear: both; }
</style>
</head>
<body>
<div class="pages">
<a href="#" data-close>Close</a>
<div class="user_capture">
<label for="username">Your Name: *</label><br/>
<input id="username" type="text" value="" name="username" /><br/>
<label for="email">Email: *</label><br/>
<input id="email" value="" name="email_address" /><br/>
<label for="phone">Phone:</label><br/>
<input id="phone" value="" name="phone" /><br/>
<label for="question">Question: </label><br/>
<textarea id="question" name="question">
</textarea><br/><br/>
<a href="#" data-user-capture>Chat</a>
</div>
<div class="chat">
<div data-status></div>
<ul id="messages"></ul>
<ul data-online>
</ul>
<div class="clr"></div>
<div class="send-area">
<input id="message" autocomplete="off" /><a href="" data-send>Send</a>
</div>
</div>
</div>
<script src="https://cdn.socket.io/socket.io-1.2.0.js"></script>
<script src="http://code.jquery.com/jquery-1.11.1.js"></script>
<script>
$(document).ready(function(){
var socket = io.connect();
var $close = $('[data-close]');
$close.unbind().bind('click', function(){
if(window.confirm("Are you sure?")) {
location.reload();
}
});
//CAPTURE
$('[data-user-capture]').unbind().bind('click', function(e){
e.preventDefault();
//hide form show chat window
$('.user_capture').hide();
$('.chat').show();
var data = {
username:$('[name="username"]').val(),
question:$('[name="question"]').val(),
}
socket.emit('user capture', data);
});
socket.on('user capture', function(data){
$('#messages').append('<li><strong>'+data.username +' says: </strong>'+data.question+'<li>');
console.log(JSON.stringify(data));
$('[data-status]').append('<strong>Status: </strong>'+data.status);
//$('[data-online]').each(data.online_users).append('<li>'+online+'</li>')
});
//SEND MESSAGE
$('[data-send]').unbind().bind('click', function(e){
e.preventDefault();
if(!$('#message').val()){
$('#message').focus();
$('#message').attr('placeholder', 'Please enter a message...');
} else {
socket.emit('send', $('#message').val());
$('#message').val('');
// return false;
}
});
socket.on('send', function(data){
$('#messages').append('<li><strong>'+data.username +' says: </strong>'+data.msg+'<li>');
});
});
</script>
</body>
</html>
index.js
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io').listen(http);
var username;
var online_users = [];
var status = 'Disconnected';
app.get('', function(req, res){
res.sendFile(__dirname + '/index.html');
});
io.on('connection', function(socket){
socket.on('user capture', function(data){
socket.username = data.username;
data.online_users.push(socket.username);
data.status = 'Connected';
io.emit('user capture', data);
console.log(data);
});
socket.on('send', function(msg){
sendData = {
msg:msg,
username:socket.username
};
io.sockets.emit('send', sendData);
});
});
http.listen(3000, function(){
console.log('listening on *:3000');
});

Resources