So i'm new in JS and i have a task for mastering Ajax Requests.I should send an email input from form to the server and a lot more,but i can not figure out how to send this data to a server that is in another folder.I lost all my nerves with this task and i dont know what to do.
So,i have a folder personal-website-server and another folder src where is my project,both folders are in another folder,the parent.
It looks like this :
./
dist < webpack bundle folder
node_modules
personal-website-server
/ package.json in personal-website-server
src
and package.json in the parent folder
Image for more understanding:
So,i should do this:
Upon clicking on the "Subscribe" button, implement the functionality for sending a user email to the server. For that, make POST Ajax request using http://localhost:3000/subscribe endpoint. The call to the server should only be made when the form is valid (the validate function )
The connection is made through a proxy to the server,idk how this thing works and i get it hard to do this task because its not so described.
Codes:
I created fetch.js in src that checks if email is valid and sends it to the server,like i understood:
import { validateEmail } from './email-validator.js'
// const express = require('express');
// const app = express();
// app.listen(3000,() => console.log('listening at 3000'));
// app.use(express.static(path.join(__dirname, 'public')));
export const sendSubscribe = (emailInput) => {
const isValidEmail = validateEmail(emailInput)
if (isValidEmail === true) {
// fetch('http://localhost:9000/subscribe', {
// method: 'post',
// body: emailInput
// }).then(function (response) {
// return response.text();
// }).then(function (text) {
// console.log(text);
// }).catch(function (error) {
// console.error(error);
// })
//createRequest(url);
app.post('/subscribe', (request, response) => {
console.log(request.body);
});
}
}
// const createRequest = (url) => {
// const httpRequest = new XMLHttpRequest(url)
// httpRequest.addEventListener('readystatechange', (url) => {
// if (httpRequest.readyState === 4) {
// console.log(httpRequest.responseText)
// }
// }); httpRequest.open('GET', url);
// httpRequest.send();
// };
But this code app is also in personal-website-server task,so i dont know how to make the connect from my app to that server.
Section where my form is available:
import { subscribe, unsubscribe, subscribeEmail } from './subscribe.js'
import { sendSubscribe } from './fetch.js'
const addSection = () => {
const sectionFour = createElement('sectionFour', 'section', 'app-section app-section--image-program', 'fourth-section')
const sectionParent = getElbyID('sectionParent', 'third-section')
const parentSection = sectionParent.parentNode
parentSection.insertBefore(sectionFour, sectionParent.nextSibling)
const heading2 = createElement('heading2', 'h2', 'program-title')
const heading2Text = document.createTextNode('Join Our Program')
heading2.append(heading2Text)
const parent = getElbyID('parent', 'fourth-section')
const heading3 = createElement('heading3', 'h3', 'program-subtitle')
const heading3Text = document.createTextNode('Sed do eiusmod tempor incididunt')
heading3.appendChild(heading3Text)
const linebreak = createElement('linebreak', 'br')
heading3.appendChild(linebreak)
const textAfterBreak = document.createTextNode('ut labore et dolore magna aliqua')
heading3.appendChild(textAfterBreak)
const form = createElement('submitFieldWrapper', 'form', 'submitFieldWrapper', 'form')
form.method = "POST";
parent.append(heading2, heading3, form)
const emailForm = createElement('emailForm', 'div', 'form-wrapper', 'emailForm')
const inputForm = createElement('inputForm', 'input', 'form-input', 'submit-info')
setAttributes(inputForm,
'type', 'text',
'placeholder', 'Email')
//create a variable to store localStorage email value
const localEmail = localStorage.getItem("Email")
if (localStorage.getItem('Email') !== null) {
inputForm.setAttribute('value', localEmail)
} else {
inputForm.setAttribute('placeholder', 'Email')
}
emailForm.appendChild(inputForm)
document.querySelector('form').addEventListener('submit', function (e) {
//create a variable to store localStorage email value
const introducedEmail = inputForm.value;
e.preventDefault()
console.log(introducedEmail)
localStorage.setItem('Email', introducedEmail)
subscribeEmail(introducedEmail)
sendSubscribe(introducedEmail)
//fetch data to /subscribe endpoint
const data = { localEmail }
const options = {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
};
fetch('/subscribe', options);
})
// const localEmail = localStorage.getItem("Email")
// const data = { localEmail }
// const options = {
// method:'POST'
// };
// fetch('/subscribe',options);
const submitForm = createElement('submitForm', 'input', 'app-section__button submit-btn', 'subscribeButton')
setAttributes(submitForm,
'type', 'submit',
'value', 'Subscribe')
form.append(emailForm, submitForm)
const isSubscribed = localStorage.getItem('isSubscribed')
if (isSubscribed === 'true') {
subscribe()
} else if (isSubscribed === 'false') {
unsubscribe()
}
}
//functions
const createElement = (elName, htmlEl, elClass, elID) => {
const elementName = document.createElement(htmlEl)
elementName.className = elClass
elementName.id = elID
return elementName
}
const getElbyID = (elName, searchedId) => {
const elementToSearch = document.getElementById(searchedId)
return elementToSearch
}
const setAttributes = (elem, ...elemArguments) => {
for (let i = 0; i < elemArguments.length; i = 2) {
elem.setAttribute(elemArguments[i], elemArguments[i 1])
}
}
export const advancedSection = () => {
addSection()
const getHeading = document.getElementById('fourth-section')
const sectionChildren = getHeading.children
sectionChildren[0].innerHTML = 'Join Our Advanced Program'
const getButton = document.getElementById('subscribeButton')
setAttributes(getButton,
'type', 'submit',
'value', 'Subscribe to Advanced Program')
getButton.className = 'app-section__button submit-btnAdvanced'
}
export default addSection
It is dinamically created and then bundeled with webpack.
Validate email function:
const VALID_EMAIL_ENDINGS = ['gmail.com', 'outlook.com', 'yandex.ru']
export const validateEmail = (email) => !!VALID_EMAIL_ENDINGS.some(v => email.includes(v))
export { VALID_EMAIL_ENDINGS as validEnding }
package.json from parent folder :
{
"name": "webpack-project",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build": "webpack",
"dev": "webpack-dev-server",
"lint": "eslint src"
},
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.16.0",
"@babel/preset-env": "^7.16.4",
"babel-loader": "^8.2.3",
"copy-webpack-plugin": "^6.0.0",
"css-loader": "^6.5.1",
"eslint": "^7.32.0",
"eslint-config-standard": "^16.0.3",
"eslint-plugin-import": "^2.25.3",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^5.1.1",
"html-webpack-plugin": "^5.5.0",
"style-loader": "^3.3.1",
"uglifyjs-webpack-plugin": "^2.2.0",
"webpack": "^5.64.2",
"webpack-cli": "^4.9.1",
"webpack-dev-server": "^4.5.0"
},
"dependencies": {
"jquery": "^3.6.0",
"request": "^2.79.0",
"uglifyjs": "^2.4.11"
}
}
webpack.config.js:
const CopyPlugin = require("copy-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const path = require("path");
var webpack = require('webpack');
const TerserPlugin = require('terser-webpack-plugin');
module.exports = {
mode: 'production',
entry: "./src/index.js",
output: {
filename: "main.js",
path: path.resolve(__dirname, "dist")
},
optimization: {
minimize: true,
minimizer: [new TerserPlugin()],
},
performance: {
hints: false,
maxEntrypointSize: 512000,
maxAssetSize: 512000
},
devServer: {
hot: true,
static: [
{
directory: path.join(__dirname, "dist")
}],
port: 9000,
proxy: {
'/api': 'http://localhost:3000'
},
},
module: {
rules: [
{
test: /\.js$/,
exclude: /(node_modules)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
},
{
test: /\.css$/,
use: [
{ loader: 'style-loader' },
{ loader: 'css-loader' },
]
}
]
},
plugins: [
new CopyPlugin({
patterns: [
{ from: "src/assets/images", to: "assets/images" },
],
}),
new HtmlWebpackPlugin({
template: 'src/index.html'
}),
new webpack.HotModuleReplacementPlugin(),
],
};
In this state that i sent to you i get the next errors:
main.js:2 POST http://localhost:9000/subscribe 404 (Not Found)
Uncaught ReferenceError: app is not defined
at HTMLFormElement.<anonymous> (main.js:2)
Now some code from personal-website server:
package.json:
{
"name": "personal-website-server",
"version": "0.0.0",
"private": true,
"scripts": {
"start": "node ./bin/www",
"dev": "nodemon ./bin/www",
"lint": "npx eslint ./",
"lint-fix": "npx eslint ./ --fix"
},
"dependencies": {
"cookie-parser": "~1.4.4",
"debug": "~2.6.9",
"express": "~4.16.1",
"morgan": "~1.9.1"
},
"devDependencies": {
"eslint": "^7.1.0",
"nodemon": "^2.0.4"
}
}
app.js:
const express = require('express');
const path = require('path');
const cookieParser = require('cookie-parser');
const logger = require('morgan');
const indexRouter = require('./routes/index');
const communityRouter = require('./routes/community');
const analyticsRouter = require('./routes/analytics');
const app = express();
global.appRoot = path.resolve(__dirname);
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', indexRouter);
app.use('/community', communityRouter);
app.use('/analytics', analyticsRouter);
module.exports = app;
www file from bin:
#!/usr/bin/env node
/**
* Module dependencies.
*/
const app = require('../app');
const debug = require('debug')('javascript-frontend-applied-server:server');
const http = require('http');
/**
* Get port from environment and store in Express.
*/
const port = normalizePort(process.env.PORT || '3000');
app.set('port', port);
/**
* Create HTTP server.
*/
const server = http.createServer(app);
/**
* Listen on provided port, on all network interfaces.
*/
server.listen(port);
server.on('error', one rror);
server.on('listening', onListening);
/**
* Normalize a port into a number, string, or false.
*/
function normalizePort(val) {
const port = parseInt(val, 10);
if (isNaN(port)) {
// named pipe
return val;
}
if (port >= 0) {
// port number
return port;
}
return false;
}
/**
* Event listener for HTTP server "error" event.
*/
function one rror(error) {
if (error.syscall !== 'listen') {
throw error;
}
const bind = typeof port === 'string'
? 'Pipe ' port
: 'Port ' port;
// handle specific listen errors with friendly messages
switch (error.code) {
case 'EACCES':
console.error(bind ' requires elevated privileges');
process.exit(1);
break;
case 'EADDRINUSE':
console.error(bind ' is already in use');
process.exit(1);
break;
default:
throw error;
}
}
/**
* Event listener for HTTP server "listening" event.
*/
function onListening() {
const addr = server.address();
const bind = typeof addr === 'string'
? 'pipe ' addr
: 'port ' addr.port;
debug('Listening on ' bind);
}
index.js from routes folder:
const express = require('express');
const router = express.Router();
const FileStorage = require('../services/FileStorage');
/* POST /subscribe */
router.post('/subscribe', async function (req, res) {
try {
if (!req.body || !req.body.email) {
return res.status(400).json({ error: "Wrong payload" });
}
if (req.body.email === '[email protected]') {
return res.status(422).json({ error: "Email is already in use" });
}
const data = {email: req.body.email};
await FileStorage.writeFile('user.json', data);
await res.json({success: true})
} catch (e) {
console.log(e);
res.status(500).send('Internal error');
}
});
/* GET /unsubscribe */
router.post('/unsubscribe ', async function (req, res) {
try {
await FileStorage.deleteFile('user.json');
await FileStorage.writeFile('user-analytics.json', []);
await FileStorage.writeFile('performance-analytics.json', []);
await res.json({success: true})
} catch (e) {
console.log(e);
res.status(500).send('Internal error');
}
});
module.exports = router;
Let me know if you need more information,i can not get an end with this task and this drives me crazy,please help.
CodePudding user response:
I fixed the problem,it was in the webpack.config.js.I didnt listened to the apis and now it is like this :
devServer: {
hot: true,
open: false,
static: [
{
directory: path.join(__dirname, "dist")
}],
port: 8080,
proxy: [{ context: ['/community', '/subscribe', '/unsubscribe'], target: 'http://localhost:3000', }],
},
And post ajax request:
const sendHttpRequest = (method, url, data) => {
return fetch(url, {
method: method,
body: JSON.stringify(data),
headers: data ? {
'Content-Type': 'application/json'
} : {}
}).then(response => {
if (response.status >= 400) {
return response.json().then(errResData => {
const error = new Error('Something went wrong!');
error.data = errResData;
throw error;
});
}
return response.json();
});
};
const sendData = (emailInput) => {
sendHttpRequest('POST', 'http://localhost:8080/subscribe', {
email: emailInput
}).then(responseData => {
console.log(responseData);
}).catch(err => {
console.log(err, err.data);
});
}
Now when i submit an email it sends to the server and creates a user.json where the email is written.