Backbone. Форма с загрузкой файлов, как обращаться?
Я хочу организовать рабочий процесс только через REST API. У меня есть форма, которая позволяет загружать изображение (enctype = "multipart/form-data" ). Как обрабатывать эту форму через магистраль? Помогите мне, пожалуйста, как я могу сериализовать его в JSON с файловым полем.
Спасибо.
Виталий
Ответы
Ответ 1
Если вы используете HTML5, вы можете использовать метод readAsDataURL из файла api, чтобы читать и хранить его на своих моделях.
Здесь код, который я использую для чтения и хранения.
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);
}
});
Ответ 2
Вы можете попробовать плагин jquery.iframe.transport.
Ответ 3
IMHO, вы не можете сериализовать файл в JSON.
Если вам нужно отправить некоторые данные вместе с файлом, вы можете отправить их в качестве параметров запроса с помощью метода POST.
www.example.com/upload?param1=value1¶m2=value2
Ответ 4
Нет хорошего способа отправить файл через AJAX. Поэтому я написал функцию для подделки - он вставляет секретный iframe в ваш DOM, который никогда не отображается, но все же работает как цель отправки вашей формы, и он устанавливает функцию для вашего ответа на вызов, который очищает дом, когда файл загружается.
У вас есть кнопка отправки формы для отправки этой функции, которую я написал. Он использует jQuery, потому что это легко и приятно, но в принципе это не должно быть строго необходимо:
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();
}
Затем у вас есть обработчик формы, который выполняет синтаксический анализ и сохранение файла, возвращая строку:
<script>window.parent.backgroundUploadComplete();</script>
Ваша форма может выглядеть так:
<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 - это div, в котором находится эта форма. Возможно, это был любой элемент DOM, ему просто нужен дом.)
Ответ 5
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
Ответ 6
Основываясь на ответе Энтони (fooobar.com/questions/345256/...), я написал решение в coffeescript на основе объекта defer.
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()
Тогда вы можете использовать его таким образом
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"
Чтобы обрабатывать его на стороне сервера (поскольку он закодирован Base64), здесь решение в RoR (на основе fooobar.com/questions/345259/...)
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
Ответ 7
Невозможно отправить файл через AJAX перед HTML5 (включая IE9).
Вам нужно синхронизировать атрибуты модели над ajax, а затем отправить еще один столбец html с файлом и затем каким-то образом синхронизировать их. Как правило, сохраните модель поверх ajax, верните идентификатор, добавьте идентификатор в другую форму и затем опубликуйте файл.
В jQuery подключаемый модуль jquery.form может помочь вам создать форму для публикации файла. Он управляет "скрытым трюком iframe", чтобы он выглядел как AJAX конечному пользователю.
Вам просто нужно потратить некоторое время на поиски "скрытого iframe трюка"...