I have an issue where I am trying to pass my file information in query parameter form to the route that I have set up to upload my AWS file and then return the url. The issue I am running into is that the form is located within the view file accessed with the /create/comment route and prepended to all of my routes is /app. In my XMLHttpRequest I am requesting /app/sign and the file query parameters, but for some reason it keeps prepending this with /app/create or /app/create/app/sign, which is why I have 404 error. Is there a way a specific method to prevent the prepending of /app/create?
Error function at xhr.send();
function sign_request(file, done) {
var xhr = new XMLHttpRequest();
console.log(xhr);
console.log(file);
xhr.open("GET", "app/sign?file_name=" + file.name + "&file_type=" + file.type);
xhr.onreadystatechange = function() {
if(xhr.readyState === 4 && xhr.status === 200) {
var response = JSON.parse(xhr.responseText);
console.log(response);
done(response);
}
};
xhr.send();
};
Error Message:
comment:139 GET http://localhost:3000/app/create/app/sign?file_name=File-name.png&file_type=image/png 404 (Not Found)
Here is my route setup:
var express = require('express');
var router = express.Router();
router.use('/app');
var config = require(path.resolve(__dirname, '..', '..','./config/config.js'));
var models = require('../models/db-index');
var fs = require('fs');
var aws = require('aws-sdk');
/*==== /SIGN ====*/
router.get('/sign', function(req, res){
aws.config.update({accessKeyId: config.awsAccessKeyId, secretAccessKey: config.awsSecretAccessKey});
var s3 = new aws.S3()
var options = {
Bucket: config.awsBucket,
Region: 'us-east-1',
Key: req.query.file_name,
Expires: 60,
ContentType: req.query.file_type,
ACL: 'public-read'
}
s3.getSignedUrl('putObject', options, function(err, data){
if(err) return res.send('Error with S3')
res.json({
signed_request: data,
url: 'https://s3.amazonaws.com/' + S3_BUCKET + '/' + req.query.file_name
});
});
});
router.get('/create/comment',function(req, res){
models.DiscoverySource.findAll({
where: {
organizationId: req.user.organizationId
}, attributes: ['discoverySourceName']
}).then(function(discoverySource){
res.render('pages/app/comment-create.hbs',{
discoverySource: discoverySource
});
});
});
Form (Accessed at /app/create/comment):
<!DOCTYPE html>
<head>
{{> app/app-head}}
</head>
<body>
{{> app/app-navigation}}
<div class="container">
<div class="col-md-12">
<div class="row-form-container">
<label for="report-link">File Attachment:</label>
<input type="file" name="fileAttachment" id="image">
<img id="preview">
</div>
</div>
<script type="text/javascript">
function upload(file, signed_request, url, done) {
var xhr = new XMLHttpRequest();
xhr.open("PUT", signed_request);
xhr.setRequestHeader('x-amz-acl', 'public-read');
xhr.onload = function() {
if (xhr.status === 200) {
done();
};
};
xhr.send(file);
}
function sign_request(file, done) {
console.log('work please');
var xhr = new XMLHttpRequest();
console.log(xhr);
console.log(file);
xhr.open("GET", "app/sign?file_name=" + file.name + "&file_type=" + file.type);
xhr.onreadystatechange = function() {
if(xhr.readyState === 4 && xhr.status === 200) {
var response = JSON.parse(xhr.responseText);
console.log(response);
done(response);
}
};
xhr.send();
};
document.getElementById("image").onchange = function() {
var file = document.getElementById("image").files[0]
if (!file) return
sign_request(file, function(response) {
upload(file, response.signed_request, response.url, function() {
document.getElementById("preview").src = response.url
});
});
};
</script>
</body>
Adding a / before app/sign when you send a request will prevent the prepending of current subpath.
Try:
xhr.open("GET", "/app/sign?file_name=" + file.name + "&file_type=" + file.type);
Related
I'm using sockjs-0.3.4.
Before change page structure, it worked normally.
However after changing some stuff. abrubtly ws.onmessage function is beginning not to called.
I checked the connection with server by looking into devtools.
It looks like getting data from the server.
Please help me to know what's the point to check out.
enter image description here
var statusWatcher = {
curPage:"",
ws: null,
wsBaseUrl :null,
uid: null,
init : function(url ){
if(statusWatcher.ws != null) return;
console.log(statusWatcher.ws);
console.log("wsBaseUrl:"+url)
statusWatcher.wsBaseUrl = url;
var browserSupport = ("WebSocket" in window)? true: false;
if(browserSupport){
statusWatcher.start();
}else{
console.log("WebSocket is Not supported by your Web Browser!");
}
//log.eventHandler(1);
},
start : function(){
baseWsURL = statusWatcher.wsBaseUrl+"/statusCheck?&uid="+statusWatcher.uid;
console.log("web socket baseurl:"+baseWsURL);
try{
statusWatcher.ws = new WebSocket(baseWsURL);
} catch (e){
console.log(e);
}
statusWatcher.ws.onopen = function() {
console.log("web socket Opened! ");
};
statusWatcher.ws.onclose = function() {
console.log("web syslog socket Closed! ");
};
statusWatcher.ws = function(err) {
console.log("web syslog socket Error: " + err);
};
statusWatcher.ws.onmessage = function(evt) {
console.log("get message...");
//console.log("page:"+curPage);
var data = evt.data;
console.log(data);
var msg;
if(curPage =="main") return;
var e = JSON.parse(data);
if(e.status =="COMPLETE"){
$("#" + e.groupId).text("complete");
$("#" + e.groupId).removeClass('run error');
$("#" + e.groupId).addClass('complete');
statusWatcher.updateScoreState(e.groupId, "COMPLETE", e.topRplRate,e.topKwdRate);
}else if(e.status == "ERROR"){
$("#" + e.groupId).text("error");
$("#" + e.groupId).removeClass('run complete');
$("#" + e.groupId).addClass('error');
statusWatcher.updateScoreState(e.groupId, "ERROR");
}else{
$("#" + e.groupId).html("running("+e.progress+"/"+e.total+")");
$("#" + e.groupId).removeClass('error complete');
$("#" + e.groupId).addClass('run');
statusWatcher.updateScoreState(e.groupId, "RUNNING");
}
};
},
}
}
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<script src="<c:url value="js/fileuploadMain/statusWatcher.js"/>"></script>
</head>
<body>
<!--header-->
<c:import url="/WEB-INF/jsp/fileupload/header.jsp" />
<!--contents-->
<div class="contents">
<div class="container" id="container">
</div>
</div>
<script>
$(document).ready(function() {
var nice = $("html").niceScroll(); // The document page (body)
$(".select-items").niceScroll({
zindex: "auto",boxzoom:false
});
$("#container").load("group.do");
calaendar.init();
var wsBaseUrl = "ws://"+document.location.host+"<c:out value="${pageContext.request.contextPath}"/>";
statusWatcher.init(wsBaseUrl);
});
</script>
</body>
</html>
statusWatcher.ws = function(err) {
console.log("web syslog socket Error: " + err);
};
I changed upper source code to the next.. Maybe I remove the function name mistakenly..
statusWatcher.ws.onerror = function(err) {
console.log("web syslog socket Error: " + err);
};
I'm trying to retrieve a picture from my API, I'm sending the data like this :
router.post('/loadpicture', function(req, res, next) {
var imgPath = __dirname + "/no_photo.png";
// var imgPath = __dirname + "/photototo.jpg";
fs.access(imgPath, fs.F_OK, (error) => {
if (error) {
console.log(error);
}
else {
res.sendFile(imgPath, (err) => { if (err) next(err); });
}
});
})
And I'm trying to display the picture like this:
var url = "data:image/png;base64,"+this.props.picture;
return (
<div>
<h1>Change your profile pictures</h1>
<img src={url} alt={'hello'}/>
</div>
);
But here is the result:
I don't know what can I do.. I tried to remove newlines and other spaces
with url.replace(/\s+/g, '') but it's not working.
UPDATE: I just replaced with this and it works :
router.post('/loadpicture', function(req, res, next) {
var imgPath = __dirname + "/no_photo.png";
var img = fs.readFileSync(imgPath);
res.writeHead(200, {'Content-Type': 'image/png' });
res.end(img.toString('base64'));
})
I am developing my mobile application using ionic framework and I want it to connect to my API through ajax. Currenty, in the mobile side, which is I am using Ionic Framework, I want to upload an image and pass it to my api through ajax. I am using Cordova for the upload but it seems it doesn't found the URL I indicated.
Here's the HTML
<ion-footer-bar class="bar bar-positive">
<div class="button-bar">
<button class="button icon-left ion-upload" ng-click="uploadImage()" ng-disabled="image === null">Upload</button>
</div>
</ion-footer-bar>
Here's the uploadImage() function in the controller (Just copied the code in a site. Forgot where) EDIT: added targetPath
$scope.uploadImage = function() {
// Destination URL
var url = "http://192.168.0.19/identificare_api/public/api/plants/image";
var targetPath = $scope.pathForImage($scope.image);
// File name only
var filename = $scope.image;
var options = {
fileKey: "file",
fileName: filename,
chunkedMode: false,
mimeType: "multipart/form-data",
params : {'fileName': filename}
};
$cordovaFileTransfer.upload(url, targetPath, options).then(function(result) {
var jsonparse = JSON.parse(result);
$scope.showAlert(jsonparse);
}
But in the upload part, I want to do it in ajax to indicate the method for the URL but the problem I don't know what put in data.
$.ajax({
url: "http://192.168.0.19/identificare_api/public/api/plants/image",
type: 'POST',
data:
success:function(json){
var jsonparse = JSON.parse(json);
alert(jsonparse);
},
error:function(){
alert("Error");
}
});
Can someone help me with this issue?
UPDATE: Applied here #Blauharley's comment below
I had another issue here. I returned the $_FILES['image']['tmp_name'] in the API side but it returns nothing but when I returned the $_FILES['image']['name'], it returned my_image.jpg. Why it doesn't have tmp_name?
$scope.uploadImage = function() {
// File for Upload
var targetPath = $scope.pathForImage($scope.image);
$scope.getBase64ImageByURL(targetPath).then(function(base64Image){
var blob = $scope.base64ToBlob(base64Image,'image/jpeg');
var fd = new FormData();
fd.append('image', blob, "my_image.jpg");
fd.append('user_token', "rLUrh37rfTozuBxmemHtlKMgH");
$.ajax({
url: 'http://192.168.0.19/identificare_api/public/api/plants/image',
type: 'POST',
data: fd,
contentType: false,
processData: false,
success:function(res){
alert(res);
},
error:function(err){
alert("Something's wrong with your api. Come on fix it!");
}
});
});
};
$scope.getBase64ImageByURL = function(url) {
var dfd = new $.Deferred();
var xhr = new XMLHttpRequest();
xhr.responseType = 'blob';
xhr.onload = function() {
var reader = new FileReader();
reader.onloadend = function() {
dfd.resolve(reader.result);
}
reader.readAsDataURL(xhr.response);
};
xhr.open('GET', url);
xhr.send();
return dfd.promise();
};
$scope.base64ToBlob = function(base64Image,toMimeType) {
var byteCharacters = atob(base64Image.replace('data:'+toMimeType+';base64,',''));
var byteNumbers = new Array(byteCharacters.length);
for (var i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i);
}
var byteArray = new Uint8Array(byteNumbers);
var blob = new Blob([byteArray], {
type: toMimeType
});
return blob;
};
ADDED: API side
public function image(){
echo json_encode($_FILES['image']['tmp_name']);
}
I have a stacked bar chart, which gains data from an api.
It works fine when loaded, and the data is displayed as it should be.
Now I wish to add new data to the chart every ten minutes, calling the same API as when loaded, the chart should refresh asynchronously and he new data and axis label need to be updated as new data is gained.
What I have done so far..
https://plnkr.co/edit/s2Os8UlpSbCWlkNP6wuA?p=preview
var ma = d3.line()
.x(function(d) { return x(parseDate(d.date)); })
.y(function(d) { return y(d.ma); });
If you use jquery, then you can send an AJAX request using the $.ajax function. Make sure you handle the response in the result's done() function, as success is deprecated.
Plain AJAX request example:
HTML:
<!DOCTYPE html>
<html>
<body>
<div id="demo"><h2>Let AJAX change this text</h2></div>
<button type="button" onclick="loadDoc()">Change Content</button>
</body>
</html>
JS:
function loadDoc() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("demo").innerHTML = this.responseText;
}
};
xhttp.open("GET", "ajax_info.txt", true);
xhttp.send();
}
Taken from here. If you mastered AJAX requests, then the next step is to write a poller, using setInterval. The first parameter should be a function which sends a request and the second should be the time between two execution in milliseconds (10000 in this case). Or you can use an existing poller. This is one I have implemented:
function Initializable(params) {
this.initialize = function(key, def, private) {
if (def !== undefined) {
(!!private ? params : this)[key] = (params[key] !== undefined) ? params[key] : def;
}
};
}
function Poller(params) {
Initializable.call(this, params);
var that = this;
this.initialize("url", window.location.href);
this.initialize("interval", 5000);
this.initialize("type", "POST");
this.initialize("method", "POST");
this.initialize("data", {});
this.initialize("strict", true);
var defaultFunction = function() {};
this.initialize("done", defaultFunction);
this.initialize("fail", defaultFunction);
this.initialize("always", defaultFunction);
this.isRunning = function() {
return !!params.intervalID;
};
this.run = function() {
if (this.strict && (this.green === false)) {
return;
}
this.green = false;
$.ajax({
url: this.url,
method: this.method,
data: this.data
}).done(function(data, textStatus, jqXHR) {
that.green = true;
that.done(data, textStatus, jqXHR);
}).fail(function(jqXHR, textStatus, errorThrown) {
that.green = true;
that.fail(jqXHR, textStatus, errorThrown);
}).always(function(param1, param2, param3) {
that.green = true;
that.always(param1, param2, param3);
});
};
this.start = function() {
if (!params.intervalID) {
this.run();
params.intervalID = setInterval(this.run.bind(this), this.interval);
}
};
this.stop = function() {
if (!!params.intervalID) {
clearInterval(params.intervalID);
params.intervalID = undefined;
}
};
}
I'm using Angular 2 with Spring MVC. I currently have an Upload component that makes an AJAX call to the Spring backend and returns a response of parsed data from a .csv file.
export class UploadComponent {
uploadFile: function(){
var resp = this;
var data = $('input[type="file"]')[0].files[0];
this.fileupl = data;
var fd = new FormData();
fd.append("file", data);
$.ajax({
url: "uploadFile",
type: "POST",
data: fd,
processData: false,
contentType: false,
success: function(response) {
resp.response = response;
},
error: function(jqXHR, textStatus, errorMessage) {
console.log(errorMessage);
}
});
};
}
This works, I get a valid response back; however, is there a more angular 2 way to pass this file to Spring and receive a response? I've been looking into creating an injectible service and using subscribe, but I've been struggling to get a response back
I ended up doing the following:
import { Component, Injectable } from '#angular/core';
import { Observable} from 'rxjs/Rx';
const URL = 'myuploadURL';
#Component({
selector: 'upload',
templateUrl: 'upload.component.html',
styleUrls: ['upload.component.css']
})
export class UploadComponent {
filetoUpload: Array<File>;
response: {};
constructor() {
this.filetoUpload = [];
}
upload() {
this.makeFileRequest(URL, [], this.filetoUpload).then((result) => {
this.response = result;
}, (error) => {
console.error(error);
});
}
fileChangeEvent(fileInput: any){
this.filetoUpload = <Array<File>> fileInput.target.files;
}
makeFileRequest(url: string, params: Array<string>, files: Array<File>) {
return new Promise((resolve, reject) => {
let formData: any = new FormData();
let xhr = new XMLHttpRequest();
for(let i =0; i < files.length; i++) {
formData.append("file", files[i], files[i].name);
}
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
resolve(JSON.parse(xhr.response));
} else {
reject(xhr.response);
}
}
};
xhr.open("POST", url, true);
xhr.send(formData);
});
}
}
I can then inject a response into my html like:
<div class="input-group">
<input type="file" id="file" name="file" placeholder="select file" (change)="fileChangeEvent($event)">
<input type="submit" value="upload" (click)="upload()" class="btn btn-primary">
</div>
<div *ngIf="response">
<div class="alert alert-success" role="alert">
<strong>{{response.myResponseObjectProperty | number}}</strong> returned successfully!
</div>
This has support for multiple file uploads. I created it as an injectable service in this plunkr:
https://plnkr.co/edit/wkydlC0dhDXxDuzyiDO3