How to Host HTML on a different server than Heroku - html

I have my index.html and the necessary .js files on heroku. Everything works fine. Now, I don't want to send my users to "myappname.herokuapp.com", so I plan to use my own website to store the .html file, but when the user taps "submit" on my HTML form, I want to execute the Herok NodeJS code.
Here is what the html looks like
<script>
const form = document.querySelector("form");
form.addEventListener("submit", async (e) => {
e.preventDefault();
try {
displayStatus("processing...");
const request = new Request("/file-upload", {
method: "POST",
body: new FormData(form),
});
const res = await fetch(request);
const resJson = await res.json();
displayResult(resJson.result);
} catch (err) {
displayStatus("an unexpected error");
console.error(err);
}
});
function displayResult(result) {
const content = `Your ID: ${result.id}`;
displayStatus(content);
}
function displayStatus(msg) {
result.textContent = msg;
}
</script>
How can I call this "/file-upload" from my HTML that is located on "mywebsite.com/index.html" while the actual NodeJS logic runs on "myappname.herokuapp.com"
I've tried to replace the "/file-upload" with "myappname.herokuapp.com/file-upload" but it doesn't work.
Again, the goal is to use what I have on Heroku, but not have the users go to "myappname.herokuapp.com" instead they should go to "mywebsite.com/index.html"
Thank you

Actually, replacing "/file-upload" with "myappname.herokuapp.com/file-upload" did the trick. The only issue is my "const request = new Request" request returning an error all the time, but Heroku logs shows a successful execution of "file-upload"

Related

How to use a Javascript file to refresh/reload a div from an HTML file?

I am using Node JS and have a JS file, which opens a connection to an API, works with the receving API data and then saves the changed data into a JSON file. Next I have an HTML file, which takes the data from the JSON file and puts it into a table. At the end I open the HTML file in my browser to look at the visualized table and its data.
What I would like to happen is, that the table (or more specific a DIV with an ID inside the table) from the HTML file refreshes itself, when the JSON data gets updated from the JS file. Kinda like a "live table/website", that I can watch change over time without the need to presh F5.
Instead of just opening the HTML locally, I have tried it by using the JS file and creating a connection with the file like this:
const http = require('http');
const path = require('path');
const browser = http.createServer(function (request, response) {
var filePath = '.' + request.url;
if (filePath == './') {
filePath = './Table.html';
}
var extname = String(path.extname(filePath)).toLowerCase();
var mimeTypes = {
'.html': 'text/html',
'.css': 'text/css',
'.png': 'image/png',
'.js': 'text/javascript',
'.json': 'application/json'
};
var contentType = mimeTypes[extname] || 'application/octet-stream';
fs.readFile(filePath, function(error, content) {
response.writeHead(200, { 'Content-Type': contentType });
response.end(content, 'utf-8');
});
}).listen(3000);
This creates a working connection and I am able to see it in the browser, but sadly it doesn't update itself like I wish. I thought about some kind of function, which gets called right after the JSON file got saved and tells the div to reload itself.
I also read about something like window.onload, location.load() or getElementById(), but I am not able to figure out the right way.
What can I do?
Thank you.
Websockets!
Though they might sound scary, it's very easy to get started with websockets in NodeJS, especially if you use Socket.io.
You will need two dependencies in your node application:
"socket.io": "^4.1.3",
"socketio-wildcard": "^2.0.0"
your HTML File:
<script type="module" src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.0/socket.io.js"></script>
Your CLIENT SIDE JavaScript file:
var socket = io();
socket.on("update", function (data) { //update can be any sort of string, treat it like an event name
console.log(data);
// the rest of the code to update the html
})
your NODE JS file:
import { Server } from "socket.io";
// other code...
let io = new Server(server);
let activeConnections = {};
io.sockets.on("connection", function (socket) {
// 'connection' is a "magic" key
// track the active connections
activeConnections[socket.id] = socket;
socket.on("disconnect", function () {
/* Not required, but you can add special handling here to prevent errors */
delete activeConnections[socket.id];
})
socket.on("update", (data) => {
// Update is any sort of key
console.log(data)
})
})
// Example with Express
app.get('/some/api/call', function (req, res) {
var data = // your API Processing here
Object.keys(activeConnections).forEach((conn) => {
conn.emit('update', data)
}
res.send(data);
})
Finally, shameful self promotion, here's one of my "dead" side projects using websockets, because I'm sure I forgot some small detail, and this might help. https://github.com/Nhawdge/robert-quest

WebSerial getPorts() method return nothing

I have tried Web Serial API.
If I use requestPort() method, like this :
<button id="connect">Connect</button>
<script>
const connectButton = document.getElementById("connect");
connectButton.addEventListener('click', async () => {
try {
const port = await navigator.serial.requestPort();
console.log(port)
} catch (e) {
console.error(e)
}
});
</script>
It's OK, to prompt the user for which device the site should be allowed to control.
But with getPorts() method, like this :
<script>
const connectButton = document.getElementById("connect");
connectButton.addEventListener('click', async () => {
try {
const ports = await navigator.serial.getPorts();
console.log(ports)
} catch (e) {
console.error(e)
}
});
</script>
I got nothing with ports.length == 0
Could anybody help this?
Thanks
A user must approve access to the device before it can be accessed. You initiate the request via:
navigator.serial.requestPort()
To get a list of ports that have already been selected/approved by the user from the permission popup you call:
navigator.serial.getPorts()
You can check out the https://webserial.io source for an example here:
https://github.com/williamkapke/webserial/blob/main/src/stores/connection.js#L41

I'm getting a 404 error when trying to render my results for my API Hack assignment

I'm working on an API Hack assignment for my class with Thinkful and my issue has been that I've been trying to make a call to spoonacular's food api and render the results onto the DOM. However, when I try to do that, All I get in return is a 404 error. I'm wondering if i did something wrong or is some unforeseen problem that is beyond my control?
I've already look at manually typing the composed URL and postman as well.
function queryParams(params) {
const queryItems = Object.keys(params).map(key => `${encodeURIComponent(key)}= ${encodeURIComponent(params[key])}`)
return queryItems.join('&');
}
function displayResults(responseJson){
console.log(responseJson);
$('#results-list').empty();
for(let i = 0; i < responseJson.results.length; i++){
$('#results-list').append(
`<li><h3>${responseJson.results[i].id},${responseJson.results[i].protein}</h3>
<p>By ${responseJson.results[i].calories}</p>
<img src='${responseJson.results[i].image}'>
</li>`
)};
$('#results').removeClass('hidden');
};
function getRecipe(query,maxResults,){
const params ={
q:query,
number: maxResults,
};
const queryString = queryParams(params)
const url = searchUrl+'?'+ queryString +'?apiKey='+ apikey;
console.log(url);
fetch(url,option)
.then(response =>{
if(response.ok){
return response.json();
}
throw new Error(response.statusText);
})
.then(response => console.log(responseJson))
.catch(err =>{
$('#js-error-message').text(`Something went wrong: ${err.message}`);
});
}
function watchForm() {
$('form').submit(event => {
event.preventDefault();
const searchRecipe = $('.js-search-recipe').val();
const maxResults = $('.js-max-results').val();
getRecipe(searchRecipe, maxResults);
});
}
$(watchForm);
It looks like you have a couple issues:
First, you're constructing an invalid url:
const url = searchUrl+'?'+ queryString +'?apiKey='+ apikey;
notice the 2 ?s
Also, when you're constructing the query params, you're adding a space between the = and the value of your param
${encodeURIComponent(key)}= ${encodeURIComponent(params[key])}
If you're using the correct path and a valid API key, fixing those things may be enough to make it work.

Login Service implementation in angularjs not working

This is my controller which is calling the login service
mod.controller("loginCtrl",function($scope,loginService,$http)
{
$scope.Userlogin = function()
{
var User = {
userid :$scope.uname,
pass:$scope.pass
};
var res = UserloginService(User);
console.log(res);
alert("login_succ");
}
});
And this is the login service code which takes the User variable and checks for username & password
mod.service("loginService",function($http,$q) {
UserloginService = function(User) {
var deffered = $q.defer();
$http({
method:'POST',
url:'http://localhost:8080/WebApplication4_1/login.htm',
data:User
}).then(function(data) {
deffered.resolve(data);
}).error(function(status) {
deffered.reject({
status:status
});
});
return deffered.promise;
// var response = $http({
//
// method:"post",
// url:"http://localhost:8080/WebApplication4_1/login.htm",
// data:JSON.stringify(User),
// dataType:"json"
// });
// return "Name";
}
});
I have created a rest api using springs which upon passing json return back the username and password in json like this
Console shows me this error for angular
You need to enable CORS for your application for guidance see this link
https://htet101.wordpress.com/2014/01/22/cors-with-angularjs-and-spring-rest/
I prefer to use Factory to do what you're trying to do, which would be something like this:
MyApp.factory('MyService', ["$http", function($http) {
var urlBase = "http://localhost:3000";
return {
getRecent: function(numberOfItems) {
return $http.get(urlBase+"/things/recent?limit="+numberOfItems);
},
getSomethingElse: function(url) {
return $http.get(urlBase+"/other/things")
},
search: function (searchTerms) {
return $http.get(urlBase+"/search?q="+searchTerms);
}
}
}]);
And then in your controller you can import MyService and then use it in this way:
MyService.getRecent(10).then(function(res) {
$scope.things = res.data;
});
This is a great way to handle it, because you're putting the .then in your controller and you are able to control the state of the UI during a loading state if you'd like, like this:
// initialize the loading var, set to false
$scope.loading = false;
// create a reuseable update function, and inside use a promise for the ajax call,
// which is running inside the `Factory`
$scope.updateList = function() {
$scope.loading = true;
MyService.getRecent(10).then(function(res) {
$scope.loading = false;
$scope.things = res.data;
});
};
$scope.updateList();
The error in the console shows two issues with your code:
CORS is not enabled in your api. To fix this you need to enable CORS using Access-Control-Allow-Origin header to your rest api.
Unhandled rejection error, as the way you are handling errors with '.error()' method is deprecated.
'Promise.error()' method is deprecated according to this and this commit in Angular js github repo.
Hence you need to change the way you are handling errors as shown below :
$http().then(successCallback, errorCallback);
function successCallback (res) {
return res;
}
function errorCallback (err) {
return err;
}
One more thing in your code which can be avoided is you have defined a new promise and resolving it using $q methods, which is not required. $http itself returns a promise by default, which you need not define again inside it to use it as a Promise. You can directly use $http.then().

AngularJS File Upload to Backend Express Server

I am trying to do a file upload using angularjs, using angular-file-upload library (https://github.com/danialfarid/angular-file-upload)
Here is my code
// ===============================My HTML File===========================
<input type="file" ng-file-select="onFileSelect($files)">
// ===============================My Controller==========================
var $scope.formObj = {
name: "Test"
};
var fileToUpload;
$scope.onFileSelect = function (file) {
fileToUpload = file[0];
};
// POSt request to /api/items
$scope.addItem = function() {
console.log($scope.formObj);
$scope.upload = $upload.upload({
url: '/api/items',
method: 'POST',
data: { myObj: $scope.formObj },
file: fileToUpload
}).success(function(data, status, headers, config) {
console.log("success");
});
};
// ================================My Backend=============================
// This is the function that will receive POST request to /api/items
exports.create = function(req, res) {
console.log(req.body); // req.body is just an empty object. ==> {}
// apparently, I found all the data to be in req._readableState.buffer[0]
// in the form of a buffer
var buffer = req._readableState.buffer[0];
// trying to console.log the buffer.toString, resulting in something similar to this
// { name: "Test", image: Object }
console.log(buffer.toString());
return res.send(200);
};
So my backend received the formObj with all its properties and values, however, the actual file data itself, whether in the form of buffer, or base64, or whatever, never gets received.
I wonder why. This is my first time working with file uploading, so I don't understand the concept.
Please point me in the right direction
If you are using Latest version of Express, you'd notice that
app.use(express.multipart()); is no longer bundled with express.
So do the following configuration changes. in express.js
var multer = require('multer');
app.use(multer({ dest: './uploads/'}));
You'd find that after doing this you would find the data and file , in req.body req.file respectively.
Hope it helps