i'm stuck with image upload to firebase database asynchronous mecanism in my project, here's my problematic:
i have a form where user put some info, the user also need to provide 4 photo to complete the upload process.
i use firebase database & firebase storage to handle this, here's the flow :
user fill form1 form2 & form3 with text based info
user select img1 img2 img3 img4 image from his computer
user clic submit all 4 image upload to firebase and give me 4 download url
i append all previously gathered information + 4 download url in a dictionary and ship it to firebase database
so the my deal is to create and ship the dictionary only when and if the 4 photo url are set, i heard about deferred/promise concept but i see a lot of Ajax request and no one with a similar issue, here is what i have for now
$("#submit-bag").click(function () {
var uploadDfdimg1 = function() {
var deferred = new $.Deferred();
var uploadTask = storageRef.child('images/' + $img1.name).put($img1);
uploadTask.on('state_changed', function(snapshot){
}, function(error) {
deferred.reject(error);
}, function() {
var downloadURL = uploadTask.snapshot.downloadURL;
console.log(downloadURL);
url1 = downloadURL;
deferred.resolve(downloadURL);
return deferred.promise();
});
}
var uploadDfdimg2 = function() {
var deferred = new $.Deferred();
var uploadTask = storageRef.child('images/' + $img2.name).put($img2);
uploadTask.on('state_changed', function(snapshot){
}, function(error) {
deferred.reject(error);
}, function() {
var downloadURL = uploadTask.snapshot.downloadURL;
console.log(downloadURL);
url2 = downloadURL;
deferred.resolve(downloadURL);
return deferred.promise();
});
}
$.when(uploadDfdimg1,uploadDfdimg2).then(
function(){console.log('double trouble success')},
function(){console.log(url1 + " deferred")},
function(){console.log(url2 + " deferred")});
var brand = $("#select1 option:selected").text()
var mail = document.getElementById('form1').value
var postal_code = document.getElementById('form2').value
var comment = document.getElementById('comment').value
//UPLOAD IMG
//uploadImg(img1,url1);
//uploadImg(img2,url2);
uploadImg(img3,url3);
uploadImg(img4,url4);
//console.log(url1);
//console.log(url2);
console.log(url3);
console.log(url4);
//PHOTO LINK VAR
var postData = {
marque: brand,
email: mail,
code_postal: postal_code,
commentaire: comment,
//PHOTO LINK
validation: 0
};
var newPostKey = firebase.database().ref().child('submission').push().key;
var updates = {};
updates['/submission/' + newPostKey] = postData;
firebase.database().ref().update(updates)
like you can see here, img3 & img4 upload themselves using the old non fonctionnal manner (downloadUrl come after the all dictionary PostData is send)
for img1 & img2 i tryed to use Deferred to see if i can get the 2 url at the same time when $.when.().then fired, normally after the success promise of the two uploadDfdimg function
the result is, i instantly get the "double trouble" log message with empty url variable, and normally after a second, the two url returned by firebase for img3 and img4
return log of the above code
how can i be able to asynchronously send 4 image to firebase, get the url, and at the end of this process, put the url in my dictionary to send it to my database ?
The question appears to ask for the following type of approach.
First a utility function, which promisifies the upload process and delivers a promise-wrapped downloadURL.
function uploadImg(img) {
return $.Deferred(function(dfrd) {
var uploadTask = storageRef.child('images/' + img.name).put(img);
uploadTask.on(
'state_changed',
function(snapshot) {},
function(error) { dfrd.reject(error); },
function() { dfrd.resolve(uploadTask.snapshot.downloadURL); }
);
}).promise();
}
Now, that utility can be used to create 4 x promises, which can then be aggregated with $.when() :
$("#submit-bag").click(function () {
var p1 = uploadImg(img1);
var p2 = uploadImg(img2);
var p3 = uploadImg(img3);
var p4 = uploadImg(img4);
$.when(p1, p2, p3, p4).then(function(downloadUrl1, downloadUrl2, downloadUrl3, downloadUrl4) {
// Whatever you want to do with downloadUrl1, downloadUrl3, downloadUrl3, downloadUrl4, ...
// ... do it somewhere in this function.
var updates = {};
updates['/submission/' + firebase.database().ref().child('submission').push().key] = {
marque: $("#select1 option:selected").text(),
email: $('#form1').val(),
code_postal: $('#form2').val(),
commentaire: $('#comment').val(),
validation: 0
};
firebase.database().ref().update(updates);
});
}
More concisely, you would probably write :
$("#submit-bag").click(function () {
var promises = [img1, img2, img3, img4].map(uploadImg);
$.when.apply(null, promises).then(function(downloadUrl1, downloadUrl3, downloadUrl3, downloadUrl4) {
// Whatever you want to do with downloadUrl1, downloadUrl3, downloadUrl3, downloadUrl4, ...
// ... do it somewhere in this function.
// etc, as above
});
}
Related
I'm running a Vue script with a text box and submit button, I'm calling an api to POST what I write in the textbox to the api and to return information back from the API, I'm getting this error mentioned in the title eventhough I've written the Javascript functions in vue as it should be?
With the script I'm first setting up a new XMLHttpRequest, initiating the header and api key for both GET and POST methods. I've then created 2 functions to get the data from the textbox and send them to the API, then making another button with the other function to send back the data.
I went through this approach because I kept getting a CORS issue and the API needed me to declare an access control origin header, is there anything I've done wrong with this code? Any help would be greatly appreciated
<script>
export default {
name: 'ProperForm'
}
methods: {
StartClient: function () {
this.get = function(Url, Callback){
var aHttpRequest = new XMLHttpRequest();
aHttpRequest.onreadystatechange = function() {
if (aHttpRequest.readyState == 4 && aHttpRequest.status == 200)
Callback(aHttpRequest.responseText);
}
aHttpRequest.open("GET", Url, true);
aHttpRequest.setRequestHeader("X-Api-Key", "eVnbxBPfn01kuoJIdfgi46TiYNv8AIip1r3WbjsX");
aHttpRequest.send(null);
}
this.post = function(Url, message, Callback) {
var aHttpRequest = new XMLHttpRequest();
aHttpRequest.onreadystatechange = function() {
if (aHttpRequest.readyState == 4 && aHttpRequest.status == 200)
Callback(aHttpRequest.responseText);
}
aHttpRequest.open("POST", Url, true);
aHttpRequest.setRequestHeader("x-api-key", "eVnbxBPfn01kuoJIdfgi46TiYNv8AIip1r3WbjsX");
aHttpRequest.send(message);
}
}
var client = new StartClient();
submitData: function () {
document.getElementById('inputBox').disabled = true;
var targetInputButton = document.getElementById("inputBox").value;
var message = '{"targetInputButton":"' + targetInputButton + '"}';
client.post('https://le75bkfcmg.execute-api.eu-west-2.amazonaws.com/dev/start-trace', message, function(response) {
document.getElementById('jobId').innerHTML = response;
});
}
sendBackData: function () {
var jobId = document.getElementById("jobId").innerHTML;
var message = '{"jobId":"' + jobId + '"}';
client.post('https://le75bkfcmg.execute-api.eu-west-2.amazonaws.com/dev/check-trace', message, function(response) {
document.getElementById('report').innerHTML = response;
});
}
}
</script>
New way I wrote var client:
StartClient: function () {
var client
},
You need put your methods object inside export and split the methods to comma
<script>
export default {
name: 'name',
methods:{
foo(){
},
bar(){
}
}
}
UPD: var client = new StartClient();
defined outside the method
I am trying to detect emotions in faces from an image uploaded. I can't seem to find any example code for emotion detection.
https://azure.microsoft.com/en-us/try/cognitive-services/my-apis/?apiSlug=face-api&country=Canada&allowContact=true
I found this
https://learn.microsoft.com/en-us/azure/cognitive-services/emotion/quickstarts/javascript
but the url endpoint doesn't work. I then tried regular face api, but even that I get resource not found.
Does anyone know what's going one?
Thanks
var FACE = new function () {
this.listen = function() {
var camera = document.getElementById('camera');
camera.addEventListener('change', function(e) {
var imageFile = e.target.files[0];
var reader = new FileReader();
var fileType;
//wire up the listener for the async 'loadend' event
reader.addEventListener('loadend', function () {
//get the result of the async readAsArrayBuffer call
var fileContentArrayBuffer = reader.result;
sendImage(fileContentArrayBuffer, fileType);
});
if (imageFile) {
//save the mime type of the file
fileType = imageFile.type;
//read the file asynchronously
reader.readAsArrayBuffer(imageFile);
}
});
function sendImage(fileContentArrayBuffer, fileType) {
$.ajax({
// NOTE: You must use the same location in your REST call as you used to obtain your subscription keys.
// For example, if you obtained your subscription keys from westcentralus, replace "westus" in the
// URL below with "westcentralus".
url: "https://westcentralus.api.cognitive.microsoft.com/face/v1.0/",
beforeSend: function(xhrObj){
// Request headers, also supports "application/octet-stream"
xhrObj.setRequestHeader("Content-Type","application/json");
// NOTE: Replace the "Ocp-Apim-Subscription-Key" value with a valid subscription key.
xhrObj.setRequestHeader("Ocp-Apim-Subscription-Key","my key");
},
//don't forget this!
processData: false,
type: "POST",
// Request body
data: new Blob([fileContentArrayBuffer], { type: fileType })
}).done(function(data) {
alert(data);
// Get face rectangle dimensions
var faceRectangle = data[0].faceRectangle;
var faceRectangleList = $('#faceRectangle');
// Append to DOM
for (var prop in faceRectangle) {
faceRectangleList.append("<li> " + prop + ": " + faceRectangle[prop] + "</li>");
}
// Get emotion confidence scores
var scores = data[0].scores;
var scoresList = $('#scores');
// Append to DOM
for(var prop in scores) {
scoresList.append("<li> " + prop + ": " + scores[prop] + "</li>")
}
}).fail(function(err) {
alert("Error: " + JSON.stringify(err));
});
}
};
};
Assuming you have your key, the request URL for Emotion API should be
https://westus.api.cognitive.microsoft.com/emotion/v1.0/recognize?
You may also want to take a look at this website. It got similar code.
Sorry I can't use comment function as I am new here and don't have enough reputation to do so.
Could you double check with your api region? Because this error occurs when there is no resource found for given api key in a region.
And for accessing emotions you will need to pass parameters to api which will give you attributes for faces in response which contains emotions.
Is there a way to display your AJAX data back in the order in which you called your AJAX requests, without using promises, also no synchronous code or jQuery, but simply pure javascript?
For example:
//file 1 takes 3 seconds & file2 takes 1 second
input: ['example1.com', 'example2.com']
output: [example1_response, example2_response]
I started by setting up a small toy problem in my HTML page. I append two placeholder <div>'s with the text wait inside my webpage & then as my url requests completed the appropriate <div>'s placeholder text was replaced. But still it doesn't achieve the end goal of loading my content based on the order in which I made my requests.
JSFIDDLE:https://jsfiddle.net/nf4p1bgf/5/
var body = document.getElementsByTagName('body')[0]
var urls = [ "website1.com", "website2.com"];
//Helper function to simulate AJAX request
function fakeAjax(url,cb) {
var fake_responses = {
"website1.com": "data from website1.com",
"website2.com": "data from website2.com"
};
var randomDelay = (Math.round(Math.random() * 1E4) % 8000) + 1000;
console.log(`Requesting: ${url}. Response time: ${randomDelay}`);
setTimeout(function(){
cb(fake_responses[url]);
},randomDelay);
}
urls.forEach(function(url) {
//creating placeholder <div>'s before AJAX data returns
var div = document.createElement("div");
div.innerHTML = "this is a place holder - please wait";
body.appendChild(div);
fakeAjax(url, function(data) {
div.innerHTML = data;
});
});
EDIT & SOLUTION JSFiddle here: https://jsfiddle.net/fa707qjc/11/
//*********** HELPERS (SEE CODE BELOW HELPERS SECTION) ***********/
var body = document.getElementsByTagName('body')[0]
var urls = ["website1.com","website2.com"];
function fakeAjax(url,cb) {
var fake_responses = {
"website1.com": "data from website1.com",
"website2.com": "data from website2.com"
};
var randomDelay = (Math.round(Math.random() * 1E4) % 8000) + 1000;
console.log(`Requesting: ${url}. Response time: ${randomDelay}`);
setTimeout(function(){
cb(fake_responses[url]);
},randomDelay);
}
function createElement(typeOfElement, text){
var element = document.createElement(typeOfElement)
element.innerHTML = text;
return element;
}
function handleResponse(url, contents){
//if I haven't recieved response from x url
if( !(url in responses)){
responses[url] = contents;
}
//defining order for response outputs
var myWebsites = ['website1.com','website2.com'];
// loop through responses in order for rendering
for(var url of myWebsites){
if(url in responses){
if(typeof responses[url] === "string"){
console.log( responses[url])
//mark already rendered
var originalText = responses[url];
responses[url] = true;
var p = createElement('p', originalText);
body.appendChild(p);
}
}
//can't render it / not complete
else{
return;
}
}
}
//*********** CODE START ***********
function getWebsiteData(url) {
fakeAjax(url, function(text){
console.log(`Returning data from ${url} w/response: ${text}`)
handleResponse(url, text);
});
}
//As we get our responses from server store them
var responses = {};
// request all files at once in "parallel"
urls.forEach(function(url){
getWebsiteData(url);
})
Use Promise.
Promise.all(urls.map(function(url) {
return new Promise(function(resolve, reject) {
request(url, function(data, error) {
if (error) {
return reject(error);
}
resolve(data);
})
});
})).then(function(results) {
console.log(results);
});
I'm using Parse.com give people an ability to share a URL from the app, to an individual "object" in Parse.com.
The below code works fine- EXCEPT for some reason the "LINK" (URL) is not coming through. All the other data comes through.
Is there a trick with Parse and sharing URL's?
My HTML is fine, I"ve pasted my javascript below.
var url = document.URL;
var objectId = url.substr(url.lastIndexOf('/') + 1);
var name;
var designer;
var itemDescription;
var price;
var link;
var image;
Parse.initialize("xxx", "xxx");
var garmentsAPI = Parse.Object.extend("garmentsAPI");
var query = new Parse.Query(garmentsAPI);
query.get(objectId, {
success: function(garments) {
console.log("success");
name = garments.get("name");
designer = garments.get("designer");
itemDescription = garments.get("itemDescription");
price = garments.get("price");
link = garments.get("link");
image = garments.get("smallImage1");
$("#designer").html(designer);
$("#name").html(name);
$("#itemDescription").html(itemDescription);
$("#price").html(price);
$("#image").attr("src", image.url());
$("#buyButton").attr('href', link);
console.log(image.url());
},
error: function(object, error) {
// The object was not retrieved successfully.
// error is a Parse.Error with an error code and message.
console.log("fail");
}
});
if your column name of file is
smallImage1 then
you can get url of file is as follows:
smallImage1._url
Hey all I'm trying to get a window populated with a table view that is populated from a network function in Titanium Studio, build: 2.1.1.201207271312. I have the data being fetched properlybut the problem is that the program continues to run without waiting for the table view to be populated properly. Here's the code:
ui.js:
bs.ui.createTransitRoutesListWindow = function() {
var winbsRoutesList = Titanium.UI.createWindow({
});
var tv2 = Ti.UI.createTableView();
tv2 = bs.ui.createbsRouteListTableView();
winbsRoutesList.add(tv2);
};
bs.ui.createbsRouteListTableView = function() {
var tv = Ti.UI.createTableView();
Ti.API.info('populating data');
var busStopList = bs.db.routeStopList();
tv.setData(busStopList);
return tv;
};
db.js:
bs.db.routeStopList = function() {
var stoplist = [];
bs.net.getRoutes(function(data) {
Ti.API.info('data length: '+data.length);
for (var i = 0;i<data.length;i++) {
stoplist.push({
title:data[i].stopName,
id: i
});
}
});
return stoplist;
}
network.js
bs.net.getRoutes = function(_cb) {
var xhr = Titanium.Network.createHTTPClient();
xhr.onload = function() {
_cb(JSON.parse(this.responseText));
Ti.API.info(this.responseText)
};
xhr.onerror = function(event) {
}
xhr.open("GET","<URL to valid JSON>", true);
//+ Ti.App.Properties.getString('currentBus','This is a string default')
xhr.send();
};
bussearch.net.getRoutes() is an AJAX operation and thus it is asynchronous. This means that the code will NOT wait for it to complete. The code will proceed while the response is going. The time it will respond is not known also.
If you want to do something after the data returns, you should do everything in the callback instead or create deferred objects like jQuery (which are basically callback containers).
//db.js
bussearch.db.routeStopList = function(callback) {
var stoplist = [];
bussearch.net.getRoutes(function(data) {
....
callback.call(this,stoplist);
});
}
//ui.js
bussearch.ui.createBussearchRouteListTableView = function(callback) {
var tv = Ti.UI.createTableView();
Ti.API.info('populating data');
bussearch.db.routeStopList(function(busStopList){
tv.setData(busStopList);
callback.call(this,tv);
});
};
//calling createBussearchRouteListTableView()
createBussearchRouteListTableView(function(tv){
//tv in here is the data
//do inside here what you want to do to tv after it's retrieved
});