NodeJS won't Properly load other Files [duplicate] - javascript

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 4 years ago.
I'm having trouble getting my NodeJS server to properly return the auxiliary files an HTML files needs. Instead of returning them to their appropriate places within the files, it does something really screwy.
Here's the code in question:
index.js:
var http = require('http');
var url = require('url');
var fs = require('fs');
var path = require('path');
var findFile = (function(basename) {
var results = {
contentType: '',
data: ''
};
var dataCSS = {
dir: '../CSS/',
contentType: 'text/css'
};
var dataHTML = {
dir: '../HTML/',
contentType: 'text/html'
};
var dataJS = {
dir: '../JS/',
contentType: 'text/javascript'
};
return function(basename) {
switch (path.extname(basename)) {
case '.css':
fs.readFile(dataCSS.dir + basename, function(err, data) {
results = {
contentType: dataCSS.contentType,
data: data
};
});
break;
case '.html':
fs.readFile(dataHTML.dir + basename, function(err, data) {
results = {
contentType: dataHTML.contentType,
data: data
};
});
break;
case '.js':
fs.readFile(dataJS.dir + basename, function(err, data) {
results = {
contentType: dataJS.contentType,
data: data
};
});
break;
default:
fs.readFile(dataHTML.dir + 'Home.html', function(err, data) {
results = {
contentType: dataHTML.contentType,
data: data
};
});
break;
}
return results;
};
})();
http.createServer(function(req, res) {
var myUrl = url.parse(req.url);
var basename = path.basename(myUrl.path);
console.log('request url: ' + req.url);
if (req.url !== '/') {
console.log('File requested: ' + basename);
} else {
basename = "Home.html";
}
console.log("Basename: " + basename);
var data = findFile(basename);
console.log(data);
res.writeHead(200, { 'ContentType': data.contentType });
res.write(data.data);
res.end();
}).listen(8080);
Home.html:
<!DOCTYPE html>
<html lang="en-US">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<link rel="stylesheet" type="text/css" href="../CSS/myApp.css">
<script src="../JS/myApp.js"></script>
<script src="../JS/myCtrl.js"></script>
</head>
<body>
<h2>myApp Test</h2>
<div class="myApp" ng-app="myApp" ng-controller="myCtrl" ng-init="quantity = 10; cost = 5" my-Directive>
<p>Color: <input type="text" style="background-color:{{myColor}}" ng-model="myColor" value="{{myColor}}"></p>
<p>Total in dollar (raw exp): {{quantity * cost}}</p>
<p>Total in dollar (span): <span ng-bind="quantity * cost"></span></p>
<p> First Name: <input type="text" ng-model="firstName"></p>
<p> Last Name: <input type="text" ng-model="lastName"></p>
<h1>Hello, {{firstName + " " + lastName}}</h1>
</div>
Are you even changing?!
</body>
</html>
A current run of my code does this:
I use "node index.js" in the console to start the server.
I navigate to "localhost:8080" in my browser for the first time, it shows nothing; there's an error in the dev window that says that I did not format the headers properly. This isn't true since I set it in the findFile method on each hit to the server. A console readout first looks like this:
The dev window in Firefox looks like this:
The next refresh loads the HTML page, but without any influence from the auxiliary files, even though the logging shows everything has been requested:
console log at this point:
Subsequent refreshes turns the page into a roulette with each of the separate files representing a number on the wheel. Instead of the HTML page, one of the others might display instead, with the looks of a text file. I'll spare the pictures; I feel like I've done too many as it is.
What am I doing wrong here? Is there a different way I should be doing this? Should I even have to do this at all? Please send help.
Thank you.

fs.readFile is asynchronous, meaning the callback you give to it doesn't happen immediately, it happens sometime later. Particularly, it happens after the findFile function returns the value. See this related question for more details.
In order for findFile to work correctly, it needs to receive a callback to call whenever any of the fs.readFile operations are finished. Also look into promises and async/await as a cleaner alternative to using callbacks.
function findFile(basename, done) {
switch (path.extname(basename)) {
case ".css":
fs.readFile(dataCSS.dir + basename, function(err, data) {
var results = {
contentType: dataCSS.contentType,
data: data,
}
// this function is the `function(results)` we call with down there
done(results)
})
break
case ".html":
// same as above
case ".js":
// same as above
default:
// same as above
}
}
function requestHandler(req, res) {
// same as before
findFile(basename, function(results) {
console.log(results)
res.writeHead(200, { ContentType: results.contentType })
res.write(results.data)
res.end()
})
}
http.createServer(requestHandler).listen(8080)

Related

Trying to read a JSON file with a JS script in HTML

I am trying to use my json file, busesNotArrived.json and put its contents in a <p>, however it is not working and the data in the JSON file is not displaying, here is my code:
<p>Buses Not Arrived:<br><br><span id="output"></p>
<script>
const fs = require('fs')
fs.readFile('json/busesNotArrived.json', 'utf8', (err, jsonString) => {
if (err) {
alert('Error reading Database:', err)
return
}
try {
const bus = JSON.parse(jsonString)
alert("Bus address is:", bus.busNumber)
document.getElementById('output').innerHTML = bus.BusNumber;
} catch(err) {
alert('Error parsing JSON string:', err)
}
})
</script>
Inside of my JSON file, this is what is stored:
{
"busRoute": 123123,
"busNumber": 123123
}
Javascript is not the same as node.js
require() is not a part of JavaScript standard and is not supported by browsers out of the box, it is the node.js module system.
You might need to directly include the modules; some of the modules might not work in the browser sandbox context.
Also, tools such as http://browserify.org/ might be useful.
And please put the error message too.
Well, I eventually figured it out, so like what #Ronnel said, you cannot use require() because that is node.js and not javascript, so you would have to use the fetch() api to get the .json file.
For anyone who would like to see the code, here it is:
<div id="myData" class='absolute1' onclick='notArrived()'><strong><u>Not Yet Arrived</u></strong><br><br></div>
<script>
fetch('json/busesNotArrived.json')
.then(function (response) {
return response.json();
})
.then(function (data) {
appendData(data);
})
.catch(function (err) {
console.log('error: ' + err);
});
function appendData(data) {
var mainContainer = document.getElementById("myData");
for (var i = 0; i < data.length; i++) {
var div = document.createElement("div");
div.innerHTML = 'Bus Number: ' + data[i].busNumber + "<br>" + 'Bus Route:' + ' ' + data[i].busRoute + "<br><br>";
mainContainer.appendChild(div);
}
}
</script>
|| Sorry about the Indents :P ||
And also, here is what was in the .json file so you can work off of it:
[
{
"id": "1",
"busNumber": "4024",
"busRoute": "44444"
},
{
"id": "2",
"busNumber": "4044",
"busRoute": "4444"
},
{
"id": "3",
"busNumber": "5024",
"busRoute": "55555"
}
]
Good Luck using this!
If you wanted more explanation, here is where I got the code from:
(https://howtocreateapps.com/fetch-and-display-json-html-javascript/)

Why do not you upload the images in Phaser?

I'm trying to upload images to Phaser in order to create an application.
I created a server with node.js
but they do not load the images, it loads a black background with a square in the center.
I edit the question:
I have added the html code where it is called Phaser.
Phaser install it with npm and function perfectly as you sample the console.
I show the image of the console on the network, as they suggested.
I hope this helps the companions to be able to help me, if I have to add more, they should just tell me.
console image
The Chrome inspector does not give me any errors, it shows that Phaser normally charges.
I have changed the configuration of my server several times without success, finally use one that I saw in another site.
This is my server.js file and the code that should be loaded.
const http = require('http')
const fs = require('fs')
const path = require('path')
http.createServer(function (request, response) {
console.log('request ', request.url)
var filePath = '.' + request.url
if (filePath == './') {
filePath = './index.html'
}
var extname = String(path.extname(filePath)).toLowerCase()
var mimeTypes = {
'.html': 'text/html',
'.js': 'text/javascript',
'.css': 'text/css',
'.json': 'application/json',
'.png': 'image/png',
'.jpg': 'image/jpg',
'.gif': 'image/gif',
'.wav': 'audio/wav',
'.mp4': 'video/mp4',
'.woff': 'application/font-woff',
'.ttf': 'application/font-ttf',
'.eot': 'application/vnd.ms-fontobject',
'.otf': 'application/font-otf',
'.svg': 'application/image/svg+xml'
}
var contentType = mimeTypes[extname] || 'application/octet-stream'
fs.readFile(filePath, function(error, content) {
if (error) {
if(error.code == 'ENOENT') {
fs.readFile('./404.html', function(error, content) {
response.writeHead(200, { 'Content-Type': contentType });
response.end(content, 'utf-8')
})
}
else {
response.writeHead(500);
response.end('Lo sentimos, consulte con el administrador del sitio para el error: '+error.code+' ..\n')
response.end()
}
}
else {
response.writeHead(200, { 'Content-Type': contentType })
response.end(content, 'utf-8')
}
})
}).listen(3000);
console.log('server corriendo en el puerto 3000')
All the files are in the same folder, because I had the images and html files in different folders, but it did not work either.
I found several questions on the site similar to mine, but none is the same, and I found no solution in them.
Can you give me any idea why the image is not loaded?
Thanks, I hope to show enough and clearly explain my goals.
Edit:
I show you the folder structure of my project:
In the main folder of the project are files package.json, server.js
and a folder with the images and the index.html file
Phaser-tuto1 {
package.json
server.js
public(folder) [
   -index.html
      -sky.png
      -platform-png
      -start.png
      -bomb.png
      -dude.png
   ]
}
I hope to clarify with this how my project is distributed.
<!doctype html>
<html lang="es">
<head>
<meta charset="UTF-8" />
<title>Making your first Phaser 3 Game - Part 1</title>
<script src="//cdn.jsdelivr.net/npm/phaser#3.11.0/dist/phaser.js"></script>
<style type="text/css">
body {
margin: 0;
}
</style>
</head>
<body>
<script type="text/javascript">
var config = {
type: Phaser.AUTO,
width: 800,
height: 600,
scene: {
preload: preload,
create: create,
update: update
}
};
var game = new Phaser.Game(config);
function preload() {
this.load.image('sky', 'sky.png')
}
function create() {
this.add.image(400, 300, 'sky')
}
function update() {
}
</script>
</body>
</html>
I use express for something like this, so I'm 100% sure this is the answer, but no harm trying.
this.load.image('sky', 'sky.png') tries to go to __dirname/sky.png which you haven't established yet. In server.js, add the line
if (filePath == './sky') {
filePath = './sky.png'
}
In phaser, you would then write:
this.load.image('sky', 'sky')
I hope this helps.
in phaser 3 you add image to scene dynamically from HTML Dom input
create a scene like this and do remeber to add dom container in game config
var Menu = new Phaser.Class({
Extends: Phaser.Scene,
key:'Menu',
initialize:
function Menu ()
{
Phaser.Scene.call(this, { key: 'Menu', active: false });
},
preload:function() {
this.load.html('browse', 'assets/forms/browse-btn.html');
},
create:function(){
var element = this.add.dom(220, 180).createFromCache('browse');
element.setScale(2.3,2);
element.setPerspective(800);
element.addListener('change');
element.on('change', function (event) {
_this.loadImage(event.target.files[0]);
});
},
loadImage:function(file){
var objectURL = URL.createObjectURL(file);
var name = file.name;
const card = this.add.image(WIDTH/2, HEIGHT/2, name);
let loader = new Phaser.Loader.LoaderPlugin(this);
loader.image(name, objectURL);
loader.once(Phaser.Loader.Events.COMPLETE, () => {
// texture loaded so use instead of the placeholder
console.log("loaded successfully");
card.setTexture(name)
});
loader.start();
},
});

How should I extract value from Url in Node Js

I recently started programming on nodeJs.
I am using Angular JS, resource to call API's as
demoApp.factory('class', function ($resource) {
return $resource('/class/:classId', { classId: '#_classId' }, {
update: { method: 'PUT' }
});
});
And in Controller, I have delete method as;
// The class object, e {classId: 1, className: "Pro"}
$scope.deleteClass = function (class) {
var deleteObj = new Class();
deleteObj.classId = class.classId;
deleteObj.$delete({classId : deleteObj.classId}, function() {
growl.success("Class deleted successfully.");
$location.path('/');
},function () {
growl.error("Error while deleting Class.");
}
);
};
Using browser, I verified call goes to :
http://localhost:3000/class/1
Now in node Js, How should I extract value from Url,
In server.js
app.use('/class', classController.getApi);
In classController.js
exports.getApi = function(req, resp){
switch(req.method) {
case 'DELETE':
if (req) {
// how to extract 1 from url.
}
else {
httpMsgs.show404(req, resp);
}
break;
I have tried ,
console.log(req.params);
console.log(req.query);
But no luck.
I am seeing
console.log(req._parsedUrl);
query: null,
pathname: '/class/1',
path: '/class/1',
Any help appreciated.
This should be a get call right ? You can use angular $http service, with method as get. Replace your app.use('/class') with app.get('/class', function). Then you can use req.param('classId') to retrieve data. I think it should work.
Try updating your app.use to app.use('/class/:classId'), then try req.params.classId
Try using req.hostname as in:
`http://host/path'
Check this answer.
Tldr;
var url = require('url');
var url_parts = url.parse(request.url, true);
var query = url_parts.query;
Also read the docs on node url.

Angular.js and Node.js - Passing input variables through controller to server.js

Just learning the MEAN stack at the moment, and I'm fiddling around with it but I'm a little lost.
What I'm trying to achieve is to utilize an external API to auto fill input fields about the tag that is initially typed.
So the question is, how do I pass the value of foo all the way to server.js for the call?
End-user enters a tag and presses 'Get Data'
Controller passes the value of tag (defined in my .ejs file as ng-model="object.tag") to the getData route
server.js takes tag and passes it into the external API URL to call
External API does its thing, returns with a nice and pretty JSON file for me.
Controller auto populates as many form fields as it can from the returned JSON.
Here are a few code bits just so you understand the structure of what I have a little more:
--index.ejs--
<input type="text" ng-model="object.tag" />
<button ng-click="grabFooInfo()">Get Data</button>
--controller.js--
$scope.grabFooInfo = function(){
$http.get('/getData').success(function(res){
// Will do stuff here after data comes back
});
};
--server.js--
app.get('/getData', function (req, res) {
var options = {
host: 'my.api.im.calling.com,
path: '/v1/fooApi/' + // #Need foo here //
headers: {
accept: "application/json"
},
method: 'GET'
};
var req = https.request(options, function (response) {
var fooData = '';
response.on('data', function (data) {
fooData += data;
});
response.on('end', function () {
res.send(fooData);
});
});
req.on('error', function (e) {
console.log('problem with request: ' + e.message);
});
req.end();
});
Am I doing my routing properly for how Node is intended to work?
How do I pass an input value to this internal function in server.js using Angular?
In client side,
HTML
<input type="text" ng-model="object.tag" />
<button ng-click="grabFooInfo(object)">Get Data</button>
JS
$scope.grabFooInfo = function(object){
$http({
url:'/getData',
method: "GET",
params: object
});
});
In Server Side,
app.get('/getData', function (req, res) {
var data = req.params.data; // it contains the value foo
})
Hope this works for you!!

AngularJS $resource 'GET' accesses the correct API, but 'PUT' and 'POST' do not

Follow up from AngularJS $resource calls the wrong API URL when using method:POST
My controller is set up like this, with Angular's $resource:
$scope.updateProduct = $resource('/api/updateProduct/:product/:param/:value',{},{
query: {method:'GET'},
post: {method:'POST'},
save: {method:'PUT', params: {brand: '#brand', param:'#param', value:'#value'}},
remove: {method:'DELETE'}
});
$scope.updateProduct.save({
product : $scope.post._id,
param: 'likes',
value: $scope.user._id
});
My server runs on NodeJS and ExpressJS. In my console, when the save operation is called, I can see:
POST /api/updateBrand/<productid>/likes/fun,%20quirky%20loud,%20boho,%20hippy 200 22ms - 2.31kb
However, my API is not being correctly accessed. For instance, if I go to the above URL in my browser, the API function is called, and my database is updated (and it is reported in my server's console). Yet when Angular does a PUT on this URL, nothing happens at all.
Interestingly, when I change $scope.updateProduct.save() to $scope.updateProduct.get(), the API is correctly called and everything works fine.
Any ideas what's going on here?
EDIT: Here's the server setup:
ExpressJS API setup:
app.get('/api/updateProduct/:product/:param/:value', api.updateProduct);
API code
exports.updateProduct = function (req, res) {
console.log("TEST")
var product = req.params.product;
var param = req.params.param;
var value = req.params.value;
var props = { $push: {} };
if(param == 'userTags'){
var oldVal = value;
value = oldVal.match(/[-'"\w]+/g);
props.$push[param];
props.$push[param] = {$each: []};
props.$push[param].$each = value;
}else{
var props = { $push: {} };
props.$push[param] = value;
}
db.products.update({"_id": ObjectId(product)}, props, function (err, record) {
if (err || !(record)) {
console.log("Lookup Error: " + err);
} else{
console.log("Updated " + product + " with " + param);
console.log(record);
res.json({obj:record})
}
});
};
It seems that your server is not waiting for a POST or PUT request, but a GET request as per your configuration.
app.get('/api/updateProduct/:product/:param/:value', api.updateProduct);
According to the ExpressJS API (http://expressjs.com/api.html), you should be able to replace the get with any valid http verb.
app.VERB(path, [callback...], callback)
app.post('/api/updateProduct/:product/:param/:value', api.updateProduct);
app.put('/api/updateProduct/:product/:param/:value', api.updateProduct);

Categories

Resources