Titanium Appcelerator HTTPClient return Array - request

i want to put the httpclient in a separate class and want to return the array of founded data.
My Code
function ServiceRequest(callback){
var data = [];
var xhr = Titanium.Network.createHTTPClient({
onload: function(e){
//Ti.API.info("Received text: " + this.responseText);
var doc = this.responseXML.documentElement;
var elements = doc.getElementsByTagName("record");
for (var r=0;r<elements.length;r++){
var name = elements.item(r).getElementsByTagName("field").item(3).textContent;
var monteur = elements.item(r).getElementsByTagName("field").item(15).textContent;
var adresse =elements.item(r).getElementsByTagName("field").item(10).textContent;
var ort = elements.item(r).getElementsByTagName("field").item(4).textContent +" - "+ elements.item(r).getElementsByTagName("field").item(5).textContent;
var date = elements.item(r).getElementsByTagName("field").item(8).textContent;
var termin
if (date !="") {
var arrayDate = date.split(".");
var newdate = arrayDate[1]+"."+arrayDate[0]+"."+arrayDate[2];
var temptermin = newdate +" - "+ elements.item(r).getElementsByTagName("field").item(9).textContent;
termin = temptermin;
};
data.push({"name":name,"monteur":monteur,"adresse":adresse,"ort":ort,"termin":termin});
callback( data );
};
},
onerror: function(e){
Ti.API.debug(e.error);
alert(e.error);
}
});
xhr.open("GET","http://theurltomyxml.com",false);
xhr.send();
}
module.exports =ServiceRequest;
the code snippet for my initialization
var ServiceRequest = require('ui/common/ServiceRequest');
request = new ServiceRequest(function(data){
});
Ti.API.info(request);
But the request is null, the array in my onLoad function is filled with data.
How can i wait until the httpRequest is ready than return the data array ?

You can use your custom function for callback like this way onload : callBack create your own callback function or you can put your callback( data ); after your forloop.
for (var r=0;r<elements.length;r++){//==your code here for parsing
}
callback( data );

Related

Can not get the array of data using Node.js and MongoDB

I am trying to fetch data from mongoDB and store those in array format bot outside of callback function I am getting that array variable as blank using Node.js.
My code is below:
exports.getCardDetails=function(req,res){
var userid=req.body.userid;
var token_id=req.body.token_id;
var userData=[];
db.f_user_login.find({_id: mongoJs.ObjectId(userid),token:token_id},function(err,doc){
if (doc.length > 0) {
db.f_card_details.find({userid:userid},function(errs,docs){
if (!errs) {
if (docs) {
for (var i = 0;i< docs.length;i++) {
var oemail=docs[i].email;
var id=docs[i]._id;
var name=docs[i].name;
var company=docs[i].company;
var position=docs[i].position;
var mobile=docs[i].mobile;
var landline=docs[i].landline;
var url=docs[i].url;
var postcode=docs[i].postcode;
var address=docs[i].address;
var isCurrentUser=docs[i].isCurrentUser;
db.f_user_profile.find({email:oemail},function(errs1,docs1){
if (!errs1) {
if (docs1) {
for(var j=0;j < docs1.length;j++){
var profileText=docs1[j].profiletext;
var biography=docs1[j].biography;
var image=docs1[j].file;
var profileid=docs1[j]._id;
}
var data={"id":id,"name":name,"company":company,"position":position,"mobile":mobile,"email":oemail,"landline":landline,"url":url,"postcode":postcode,"address":address,"profileText":profileText,"biography":biography,"image":image,"isCurrentUser":isCurrentUser,"profile_id":profileid};
userData.push(data);
}
}
})
}
console.log('user',userData);
var sdata={"statusCode": 200,"data":userData ,"message": "Your card details has been fetched successfully"};
res.send(sdata);
}
}
})
}else{
var data={"statusCode": 404,"error": "Not Found","message":"Invalid User"};
res.send(data);
}
})
}
Here I am pushing all data into userData array and trying to send those as response but here my problem is inside the loop all data are pushing to that array but console.log('user',userData); is showing blank while sending those data as response. I need to send those data as response.
userData is filled in db.f_user_profile.find callback, that's where you should move res.send(sdata); as well. Also I suggest to convert to async/await if you are using node7:
exports.getCardDetails = async function(req,res){
var userid=req.body.userid;
var token_id=req.body.token_id;
var userData=[];
const user = await db.f_user_login.find({_id: mongoJs.ObjectId(userid),token:token_id}).next();
if(user) {
const cards = await db.f_card_details.find({userid:userid}).toArray();
for (var i = 0;i < cards.length;i++) {
var email=docs[i].email;
var id=docs[i]._id;
var name=docs[i].name;
var company=docs[i].company;
var position=docs[i].position;
var mobile=docs[i].mobile;
var landline=docs[i].landline;
var url=docs[i].url;
var postcode=docs[i].postcode;
var address=docs[i].address;
var isCurrentUser=docs[i].isCurrentUser;
const profiles = await db.f_user_profile.find({email}).toArray();
for(var j=0; j < profiles.length;j++) {
var profileText=docs1[j].profiletext;
var biography=docs1[j].biography;
var image=docs1[j].file;
var profile_id=docs1[j]._id;
var data={id,name,company,position,mobile,email,landline,url,postcode,address,profileText,biography,image,isCurrentUser,profileid};
userData.push(data)
}
}
console.log('user',userData);
var sdata={"statusCode": 200,"data":userData ,"message": "Your card details has been fetched successfully"};
res.send(sdata);
} else {
var data={"statusCode": 404,"error": "Not Found","message":"Invalid User"};
res.send(data);
}
}

AngularJS promise through tow loops

Have some trouble with Angular promise between two loops... First loop walk through an array of value, and for each value, make a PouchDB Query to retrieve some datas. Finally, would like to return to controller a JSON Object that would look like :
{
items: [
{
"attribute": "some value"
},
{
"attribute": "some other value"
},
...
],
"a_total": "some_total",
"another_total": "some_other_total"
}
In this object, "items"
Basically, put the code in a function that looks like :
var _stockByAreas = function(){
var deferred = $q.defer();
var data = {}; // Final datas to return to controller
// Get first array to loop into
var storageAreas = storageAreaService.storageAreaList();
var areas = []; // All of area
// Walk across array
angular.forEach(storageAreas, function(zone){
var area = {}; // First object to return
area.id = zone.id;
area.libelle = zone.libelle;
// Then make a PouchDB query to get all datas that involved
MyKitchenDB.query(function(doc, emit){
emit(doc.storage);
}, { key: area.id, include_docs: true }).then(function (result) {
area.sRef = "tabsController.addTo({id: '" + area.id + "'})";
area.nbProduct = 0;
area.totalQuantity = 0;
area.totalValue = 0;
// ... process result
if(result.rows.length > 0){
// Some results, so... let's go
area.sRef = "tabsController.outFrom({id: '" + area.id + "'})";
var rows = result.rows;
// Counter initialization
var total = 0;
var value = 0;
angular.forEach(rows, function(row){
total++;
var stocks = row.doc.stock;
angular.forEach(stocks, function(stock){
var nearOutOfDate = 0;
var nearStockLimit = 0;
quantity += stock.quantity;
value += stock.quantity * stock.price;
// Evalue la date de péremption
var peremptionDate = moment(stock.until);
var currentDate = moment();
if(currentDate.diff(peremptionDate, 'days') <= 1){
nearOutDate += 1;
}
});
area.nbProduct = total;
area.qteTotale = quantity;
area.valeur = value;
if(quantite == 1){
nearLimitOfStock += 1;
}
areas.push(area); // Add result to main array
});
}
}).catch(function (err) {
// Traite les erreurs éventuelles sur la requête
});
/**
* Hey Buddy... what i have to do here ?
**/
data.items = areas;
data.nearLimitOfStock = nearLimitOfStock;
data.nearOutOfDate = nearOutOfDate;
});
deferred.resolve(data);
return deferred.promise;
}
... But, console returns that "areas" is not defined, and other value too...
I think i don't really understand how promises runs...
Someone is abble to explain why i can't get the result that i expect in my case ?
Thx
Your code is too long, I just give you the approach.
Use $q.all() to ensure all your queries are completed. And use deferred.resolve(data) whenever your data for each query is arrived.
var _stockByAreas = function() {
var query = function(zone) {
var queryDef = $q.defer();
// timeout is for query and response simulations
setTimeout(function() {
// ...
queryDef.resolve( {data: 'MeTe-30'} );
}, 1000);
return queryDef.promise;
}
var promises = [];
angular.forEach(storageAreas, function(zone) {
// ...
promises.push( query(zone) );
});
return $q.all(promises);
}
_stockByAreas().then(function(res) {
// res[0] resolved data by query function for storageAreas[0]
// res[1] resolved data by query function for storageAreas[1]
// ...
});

Saving Location of Scraped Image to DB - Node/MEAN

After scraping an image I'm able to download to a folder using request. I would like to pass along the location of this image to my Mongoose collection.
In the callback I think there should be a way to save the location so I can pass this along when saving my model object.
exports.createLook = function(req, res) {
var url = req.body.image;
var randomizer = '123456';
var download = function(url, filename, callback) {
request(url)
.pipe(fs.createWriteStream(filename))
.on('close', callback);
};
download(url, '../client/assets/images/' + randomizer + '.jpg', function() {
console.log('done');
// do something?
});
// now get model details to save
var newLook = new Look();
newLook.title = req.body.title;
newLook.image = // image location
newLook.save(function(err, look) {
if(err) return res.send(500);
} else {
res.send(item);
}
}
Assuming that 'randomizer' will be generated I would do:
exports.createLook = function(req, res) {
var url = req.body.image;
var randomizer = getSomthingRandom();
var download = function(url, filename, callback) {
request(url)
.pipe(fs.createWriteStream(filename))
.on('close', callback(filename);
};
download(url, '../client/assets/images/' + randomizer + '.jpg', function(filename) {
console.log('done');
// now get model details to save
var newLook = new Look();
newLook.title = req.body.title;
newLook.image = filename;
....
});

Can't $update or $set ~ "undefined is not a function" ~ AngularFire

What I'm trying to do:
Update the status to "TAKEN" when the chat is closed.
Issue:
Can't get $scope.currentChat.$set() or $scope.currentChat.$update() to work when trying to update the status. (See the $scope.close() function.)
What I've tried:
Various methods including $set, $update; I don't know. A lot of things. Been researching this for several hours, and can't find a solution that works.
NOTES:
$scope.currentChat.$set({status:"TAKEN"}); Doesn't work.
$scope.currentChat.$getRecord('status'); Works. Returns:
Object {$value: "OPEN", $id: "status", $priority: null}
So what exactly is going on here? Why can't I seem to set the status to TAKEN?
The issue is currently in the $scope.close() function, when trying to update the status:
// $SCOPE.CLOSE
// - Closes the current ticket.
$scope.close = function() {
// $scope.ticketObject.status = "TAKEN";
// $scope.currentChat.$set({status:"TAKEN"});
console.log("===========================");
console.log("STATUS:");
console.log($scope.currentChat.$getRecord('status'));
console.log($scope.currentChat['status']);
console.log("===========================");
$scope.ticketObject = {};
$scope.ticket = false;
$scope.toggle();
}
Here's my code:
bloop.controller('HomeCtrl', ['$scope', '$firebase', function($scope, $firebase) {
console.log("HomeController!");
var url = 'https://**********.firebaseio.com/tickets/';
var ref = new Firebase(url);
// $SCOPE.CREATETICKET
// - This function makes a connection to Firebase and creates the ticket.
$scope.createTicket = function() {
$scope.tickets = $firebase(ref).$asArray();
$scope.tickets.$add($scope.ticketObject).then(function(r) {
var id = r.name();
$scope.currentFBID = id;
$scope.syncTickets();
console.log("===========================");
console.log("CREATED TICKET: " + $scope.currentFBID);
console.log("URL: " + url + $scope.currentFBID);
console.log("===========================");
});
}
// $SCOPE.SYNCTICKETS
// - This function makes a connection to Firebase and syncs the ticket with the $scope to easily update the tickets.
$scope.syncTickets = function() {
var ticketRefURL = new Firebase(url + $scope.currentFBID);
$scope.currentChat = $firebase(ticketRefURL).$asArray();
$scope.currentChat.$save($scope.ticketObject);
var archiveRefURL = new Firebase(url + $scope.currentFBID + "/archive");
$scope.currentChat.archive = $firebase(archiveRefURL).$asArray();
console.log("===========================");
console.log("SAVED TICKET: " + $scope.currentFBID);
console.log("URL: " + ticketRefURL);
console.log("ARCHIVE URL: " + archiveRefURL);
console.log("===========================");
}
// $SCOPE.POST
// - This function pushes whatever is typed into the chat into the chat archive.
// - $scope.ticketObject.archive (is an array of objects)
$scope.post = function(name) {
// Push to ticketObject.archive array...
$scope.ticketObject.archive.push({
"name" : name,
"text" : $scope.chatText
});
// Logging the array to make sure it exists...
console.log("===========================");
console.log("CHAT ARCHIVE:");
console.log($scope.ticketObject.archive);
console.log("===========================");
$scope.currentChat.archive.$add({
"name" : name,
"text" : $scope.chatText
});
// This resets the text area so it's empty...
$scope.chatText = "";
} // WORKS
// $SCOPE.CLOSE
// - Closes the current ticket.
$scope.close = function() {
// $scope.ticketObject.status = "TAKEN";
// $scope.currentChat.$set({status:"TAKEN"});
console.log("===========================");
console.log("STATUS:");
console.log($scope.currentChat.$getRecord('status'));
console.log($scope.currentChat['status']);
console.log("===========================");
$scope.ticketObject = {};
$scope.ticket = false;
$scope.toggle();
}
// $SCOPE.TOGGLE
// - This function toggles the chat to be either open or closed.
$scope.toggle = function() {
if($scope.toggleState === false) {
$scope.toggleState = true;
$scope.checkTicket();
} else if($scope.toggleState === true) {
$scope.toggleState = false;
}
}
// $SCOPE.CHECKTICKET
// - This function checks to see if there's an existing ticket.
// - If there's not an existing ticket, it creates one.
$scope.checkTicket = function() {
if($scope.ticket === false) {
// Generate New Ticket Data
$scope.ticketObject = newTicket();
// Create the Ticket
$scope.createTicket();
// Ticket now exists.
$scope.ticket = true;
}
}
function newTicket() {
var ticketID = generateTicketID();
var newTicket = {
id: ticketID,
status: "OPEN",
name: "N/A",
email: "N/A",
date: generateDate(),
opID: "Unassigned",
opName: "Unassigned",
archive: [],
notes: []
}
return newTicket;
}
function generateTicketID() {
var chars = "0123456789ABCDEFGHJKLMNPQRSTUVWXYZ";
var result = '';
for(var i=12; i>0; --i) {
result += chars[Math.round(Math.random() * (chars.length - 1))];
}
return result;
}
function generateDate() {
var today = new Date();
var dd = today.getDate();
var mm = today.getMonth() + 1;
var yyyy = today.getFullYear();
if(dd < 10) {
dd = '0' + dd;
}
if(mm < 10) {
dd = '0' + mm;
}
var date = mm + "/" + dd + "/" + yyyy;
return date;
}
}]);
$update and $set are part of the $firebase API. You are attempting to call them on the synchronized array returned by $asArray(), which is a $FirebaseArray instance. That has its own API, which includes neither update nor set.

Backbone. Form with file upload, how to handle?

I want to organize the workflow only through the REST API. I have a form that allows to upload image (enctype="multipart/form-data"). How do I handle this form via backbone? Help me please, how I can to serialize it into JSON with a file field.
Thanks.
Vitaliy
If you are using HTML5, you can use the readAsDataURL method from the file api to read and store it on your models.
Here's the code i use to read and store.
var Image = Backbone.Model.extend({
readFile: function(file) {
var reader = new FileReader();
// closure to capture the file information.
reader.onload = (function(theFile,that) {
return function(e) {
//set model
that.set({filename: theFile.name, data: e.target.result});
};
})(file,this);
// Read in the image file as a data URL.
reader.readAsDataURL(file);
}
});
You could try the jquery.iframe.transport plugin.
IMHO, you cannot serialize a file into JSON.
If you need to send some data along with the file you can send them as query params with POST method.
www.example.com/upload?param1=value1&param2=value2
There's no good way to submit a file via AJAX. So I wrote a function to fake it--it inserts a secret iframe into your DOM that is never visible but still works as a target to submit your form on, and it installs a function for your response to call that cleans house when the file is uploaded.
Have your upload form's submit button fire this function I wrote. It uses jQuery because it's easy and nice, but in principle that shouldn't be strictly necessary:
function backgroundUpload(form, container) {
$(container).append('<iframe name="targetFrame" id="targetFrame" style="display: none; height: 0px; width:0px;" ></iframe>');
$(form).attr('target', 'targetFrame');
window.backgroundUploadComplete = function() {
//clear your form:
$(form).find(':file').val('');
$(form).find(':text').val('');
//do whatever you do to reload your screenful of data (I'm in Backbone.js, so:)
window.Docs.fetch().complete( function() { populateDocs(); });
//get rid of the target iframe
$('#targetFrame').remove();
};
$(form).submit();
}
Then have your form handler that does your file parsing and saving return the string:
<script>window.parent.backgroundUploadComplete();</script>
Your form can look like:
<form id="uploadForm" method="POST" action="/your/form/processor/url" enctype="multipart/form-data">
<input type="file" name="file"/>
<!-- and other fields as needed -->
<input type="button" onClick="backgroundUpload(this.form, $('#documents'));" value="Upload" />
</form>
(#documents is the div that this form lives in. Could probably be any DOM element, it just needs a home.)
events : {
"click #uploadDocument" : "showUploadDocumentDetails",
"change #documents" : "documentsSelected",
"click .cancel-document" : "cancelDocument"
},
showUploadDocumentDetails : function(event) {
$('#id-gen-form').attr("enctype","multipart/form-data");
$('#id-gen-form').attr("action",this.model.url);
var config = {
support : "image/jpg,image/png,image/bmp,image/jpeg,image/gif", // Valid file formats
form: "id-gen-form", // Form ID
dragArea: "dragAndDropFiles", // Upload Area ID
uploadUrl: this.model.url // Server side upload url
};
initMultiUploader(config);
if($('#uploadDocument').attr("checked")){
$('#id-documentCategory-div').show();
$('#id-documentName-div').show();
this.model.set({"uploadDocument": "YES"},{silent: true});
}
else{
$('#id-documentCategory-div').hide();
$('#id-documentName-div').hide();
this.model.set({"uploadDocument": "NO"},{silent: true});
}
},
cancelDocument : function(event) {
var targ;
if (!event) event = window.event;
if (event.target) targ = event.target;
else if (event.srcElement) targ = event.srcElement;
$('#' + event.target.id).parent().parent().remove();
var documentDetails = this.model.get("documentDetails");
documentDetails = _.without(documentDetails, _(documentDetails).find(function(x) {return x.seqNum == event.target.id;}));
this.model.set({
"documentDetails" : documentDetails
}, {
silent : true
});
},
documentsSelected : function(event) {
/*var targ;
if (!event) event = window.event;
if (event.target) targ = event.target;
else if (event.srcElement) targ = event.srcElement;
if (targ.nodeType == 3) // defeat Safari bug
targ = targ.parentNode;
var files = event.target.files; // FileList object
var html = [];
var documentDetails = [];
$(".files").html(html.join(''));
var _this = this;
_this.model.set({
"documentDetails" : documentDetails
}, {
silent : true
});
var seqNum = 0;
for(var i=0; i< files.length; i++){
(function(file) {
html.push("<tr class='template-upload' style='font-size: 10px;'>");
html.push("<td class='name'><span>"+file.name+"</span></td>");
html.push("<td class='size'><span>"+file.size+" KB <br/>"+file.type+"</span></td>");
//html.push("<td><div class='progress progress-success progress-striped active'style='width: 100px;' role='progressbar' aria-valuemin='0' aria-valuemax='100' aria-valuenow='0'><div class='bar' style='width:0%;'></div></div></td>");
if(LNS.MyesqNG.isMimeTypeSupported(file.type)){
if(!LNS.MyesqNG.isFileSizeExceeded(file.size)){
html.push("<td class='error' colspan='2'></td>");
var reader = new FileReader();
console.log(reader);
reader.onload = function(e) {
var targ;
if (!e) e = window.event;
if (e.target) targ = e.target;
else if (e.srcElement) targ = e.srcElement;
if (targ.nodeType == 3) // defeat Safari bug
targ = targ.parentNode;
console.log(e.target.result);
var content = e.target.result;
var document = new Object();
document.name = file.name;
document.type = file.type;
document.content = content;
document.seqNum = "document"+seqNum;
seqNum++;
documentDetails.push(document);
// _this.model.set({"documentDetails" : documentDetails},{silent:true});
};
reader.readAsDataURL(file, "UTF-8");
}else{
seqNum++;
html.push("<td class='error' colspan='2'><span class='label label-important'>Error</span> Too long</td>");
}
}else{
seqNum++;
html.push("<td class='error' colspan='2'><span class='label label-important'>Error</span> Not suported</td>");
}
html.push("<td><a id='document"+i+"' class='btn btn-warning btn-mini cancel-document'>Cancel</a></td>");
html.push("</tr>");
})(files[i]);
}
$(".files").html(html.join(''));*/
}
LNS.MyesqNG.isMimeTypeSupported = function(mimeType){
var mimeTypes = ['text/plain','application/zip','application/x-rar-compressed','application/pdf'];
if($.inArray(mimeType.toLowerCase(), mimeTypes) == -1) {
return false;
}else{
return true;
}
};
LNS.MyesqNG.isFileSizeExceeded = function(fileSize) {
var size = 2000000000000000000000000000;
if(Number(fileSize) > Number(size)){
return true;
}else{
return false;
}
};
Use this, it can work but not more than 5 MB file
Based on Anthony answer (https://stackoverflow.com/a/10916733/2750451), I've written a solution in coffeescript based on a defer object.
readFile: (file) =>
def = $.Deferred()
reader = new FileReader()
reader.onload = (ev) =>
def.resolve
name: file.name
binary: ev.target.result
reader.onerror = ->
def.reject()
reader.readAsDataURL(file)
def.promise()
Then, you could use it this way
readFile(file)
.done (parsedFile) =>
# do whatever you want with parsedFile
#model.set
image_name: parsedFile.name
image: parsedFile.binary
#model.save
.fail ->
console.log "readFile has failed"
To handle it on the server side (because it's Base64 encoded), here the solution in RoR (based on https://stackoverflow.com/a/16310953/2750451)
my_object.image = decode_image(params[:image])
my_object.image.name = params[:image_name]
def decode_image(encoded_file)
require 'base64'
image_data_string = split_base64(encoded_file)[:data]
Base64.decode64(image_data_string)
end
def split_base64(uri)
if uri.match(%r{^data:(.*?);(.*?),(.*)$})
return {
type: $1, # "image/png"
encoder: $2, # "base64"
data: $3, # data string
extension: $1.split('/')[1] # "png"
}
end
end
To ellaborate on Anthony Chua's answer. You need to add Image handling to Backbone.Form.editors like
Backbone.Form.editors.Image = Backbone.Form.editors.Text.extend({
tagName: 'div',
events: {
'change input[type=file]': 'uploadFile',
'click .remove': 'removeFile'
},
initialize: function(options) {
_.bindAll(this, 'filepickerSuccess', 'filepickerError', 'filepickerProgress');
Backbone.Form.editors.Text.prototype.initialize.call(this, options);
this.$input = $('<input type="hidden" name="'+this.key+'" />');
this.$uploadInput = $('<input type="file" name="'+this.key+'" accept="image/*" />');
this.$loader = $('<p class="upload-status"><span class="loader"></span> please wait..</p>');
this.$error = $('<p class="upload-error error">Error</p>');
this.$list = $('<ul class="file-list">');
},
// return an array of file dicts
getValue: function() {
var val = this.$input.val();
return (val ? JSON.parse(val) : [])[0].value;
},
setValue: function(value) {
var str, files = value;
if (_(value).isObject()) {
str = JSON.stringify(value);
} else {
files = value ? JSON.parse(value) : [];
}
this.$input.val(str);
this.updateList(files);
},
render: function(options) {
Backbone.Form.editors.Text.prototype.render.apply(this, arguments);
this.$el.append(this.$input);
this.$el.append(this.$uploadInput);
this.$el.append(this.$loader.hide());
this.$el.append(this.$error.hide());
this.$el.append(this.$list);
return this;
},
uploadFile: function() {
var fileInput = this.$uploadInput.get(0);
var fileObj = fileInput.files[0]
var reader = new FileReader();
var that = this;
// closure to capture the file information.
reader.onload = function(file){
var dataURL = reader.result;
var fileValue = {
value: dataURL,
name: fileObj.name,
content_type: fileObj.type
}
that.filepickerSuccess(fileValue);
};
// Read in the image file as a data URL.
reader.readAsDataURL(fileObj);
},
filepickerSuccess: function(files) {
console.log('File (raw)', files);
this.$loader.hide();
this.$error.hide();
this.$uploadInput.val('');
// when uploading one file, it returns just an object
if (!_(files).isArray()) { files = [files]; }
// turn response array into a flatter array of objects
var newFiles = _(files).map(function(file, index) {
return {
url: "#",
value: file.value,
filename: file.name,
key: index,
content_type: file.type
};
});
console.log('File (processed)', newFiles);
this.setValue(newFiles);
},
filepickerError: function(msg) {
console.debug('File error', msg);
this.$loader.hide();
this.$error.show();
},
filepickerProgress: function(percent) {
this.$loader.show();
this.$error.hide();
},
updateList: function(files) {
// this code is currently duplicated as a handlebar helper (I wanted to let this
// backbone-forms field stand on its own)
this.$list.empty();
_(files).each(function(file) {
var a = $('<a>', {
target: '_blank',
href: file.url,
text: file.filename + ' (' + file.content_type + ') '
});
var li = $('<li>').append(a);
li.append(a, ' ', $('<i class="icon-remove"></i>').data('key', file.key));
this.$list.append(li);
}, this);
this.$list[files.length ? 'show' : 'hide']();
},
removeFile: function(ev) {
if (ev) ev.preventDefault();
var files = this.getValue();
this.setValue([]);
}
});
You can use above code as follows
var ImgSlot = Backbone.Model.extend({
defaults: {
},
schema: {
imageField: {
type: "Image"
}
}
})
Render form using:
this.form = new Backbone.Form({
model: new ImgSlot(),
submitButton: "Example Image file input handling"
}).render();
var errors = that.form.commit({validate: true})
if(errors != null)
{
return false;
}
var data = that.form.model.attributes;
console.debug(data.imageField); // Will return base64 of image selected.
It is not possible to submit a file over AJAX before HTML5 (including IE9).
You need to sync the model attributes over ajax, and then send another html form post with the file, and then sync them up somehow. Generally, save the model over ajax, get an id back, add the id to the other form, and then post the file.
The jQuery plug in "jquery.form" may help you to construct a form to post the file. It manages the "hidden iframe trick" so that it looks like AJAX to the end user.
You might just need to spend some time googling "hidden iframe trick" ...

Resources