EmberJS file upload via jquery-file-upload - ember.js

I have an Ember.js controller and I'm attempting to send a file to my rails controller with jquery file upload.
I started with this:
myControllerAction: ->
$('#fileupload').fileupload(
url: "/api/v1/comics"
dataType: 'json'
formData:
comic: {
title: self.get('comicTitle')
prompt_one_id: self.get('prompts')[0].get('id')
prompt_two_id: self.get('prompts')[1].get('id')
}
)
Which did work, but it sent the form as soon as a file was selected. I want to do it all when the user submits the form. So I tried this:
didInsertElement: ->
$('#fileupload').fileupload(
url: "/api/v1/comics"
dataType: 'json'
formData:
comic: {
title: self.get('comicTitle')
prompt_one_id: self.get('prompts')[0].get('id')
prompt_two_id: self.get('prompts')[1].get('id')
}
add: (e, data) ->
data.submit()
progressall: (e, data) ->
progress = parseInt(data.loaded / data.total * 100, 10)
$('#progress .bar').css('width', progress + '%')
)
myControllerAction: ->
self = #
$('#fileupload').fileupload('add')
However that doesn't work. It throws a javascript error:
Uncaught Error: cannot call methods on fileupload prior to initialization; attempted to call method 'add'
I thought setting everything up on element insertion would be initializing the object. So I'm not sure where I'm going wrong. Anyone have any suggestions?
EDIT: To add template
<form enctype="multipart/form-data">
<div class="control-group">
<label class="control-label" for="inputTitle">Title</label>
<div class="controls">
{{input type="text" valueBinding="comicTitle"}}
{{input type="file" id="fileupload" valueBinding="comicFile"}}
</div>
</div>
<button {{action myControllerAction}} id="upload_comic" class="btn btn-inverse">Upload Comic</button>
<div id="progress">
<div class="bar" style="width: 0%;"></div>
</div>
</form>

Not sure what's the cause of the error, but try to do it with the afterRender callback. Also use this.$('#fileupload') instead of $('#fileupload'). Code:
didInsertElement: ->
Ember.run.scheduleOnce('afterRender', this, 'setupFileUpload')
setupFileUpload: ->
$('#fileupload').fileupload(
url: "/api/v1/comics"
dataType: 'json'
formData:
comic: {
title: self.get('comicTitle')
prompt_one_id: self.get('prompts')[0].get('id')
prompt_two_id: self.get('prompts')[1].get('id')
}
add: (e, data) ->
data.submit()
progressall: (e, data) ->
progress = parseInt(data.loaded / data.total * 100, 10)
$('#progress .bar').css('width', progress + '%')
)

Related

How to get response back from Django API to Calling HTML Page i am posting an image to Api?

How I can call a Django API from another Django Project (or from any other project) and get the response back after some processing on the same calling page (the page from which I called the API)
I am calling the API from form action ....but API shows the response in a new blank page
Here is API CODE: (//skipping some code to avoid confusion)
def IdealWeight(request):
#defining a list of data to send back to html
list_of_data=[]
list_of_data.append(name)
list_of_data.append(fatherName)
list_of_data.append(registration)
print(list_of_data)
# outPut_Data = ast.literal_eval(list_of_data)
# return render(request,'LibraryForm.html',{'data1':outPut_Data})
return JsonResponse(list_of_data,safe=False)
I want list_of_data on the calling page in some variable.
Here is my HTML Code from which i am calling the API:
<form action="http://127.0.0.1:8000/idealweight/?image/" method="POST" enctype="multipart/form-data">
{% csrf_token %}
<input type="file" class="form-control-file" name="image" onchange="readURL(this);" required>
<input type="submit" class=" btn btn-primary" title="Process" value="Process" id="processButton">
</div>
{{ data1 }}
</form>
From HTML page, I am sending a picture to API (API build in Django)
and from that, I want to send an array or list of data extracted from the image and want to show that on same HTML page....................from which I called the API how I can do that?
hope I am clear what I want?
Using an Ajax call would be better choice. you would be doing something along the line.
$(document).ready(function (e) {
$('#upload').on('click', function () {
var file_data = $('#file').prop('file');
var form_data = new FormData();
form_data.append('file', file_data);
$.ajax({
url: 'http://127.0.0.1:8000/idealweight/?image/',
contentType: false,
data: form_data,
type: 'post',
success: function (response) {
// use response to update html
},
error: function (response) {
// use response to update html
}
});
});
});
and your template would be something like
<input type="file" id="file" name="file"/>
<button id="upload" type="button">Process</button>
note: you might get cross origin request block error. so you have to allow that explicitly.

On demand handlebars compiling within Ember.view component

I'm trying to append HTML elements to the UI upon user clicks, such elements would be assembled and precompiled within a view component like this:
NewElementView = Ember.View.extend(
tagName: 'li',
click: ((event)->
this.insertElement()
),
blueprint: (->
'<div id="{{dom_id}}">
<textarea></textarea>
<button {{action "submit"}}>Save</button>
</div>'
).property()
insertElement: (->
html = this.get("blueprint")
template = Ember.Handlebars.compile(html)
context = { dom_id: "foo" }
Ember.$(template(context)).appendTo("#container")
)
)
When running Ember.Handlebars.compile(html) line it raises Uncaught TypeError: Cannot read property 'push' of undefined
Any idea of why?
Thanks in advance!
Ember.Handlebars.compile expects an object with a data property.
What you are trying to do can be achieved with the following
template
<script type="text/x-handlebars" data-template-name="my-custom-view">
<div {{bind-attr id='view.dom_id'}}>
<textarea></textarea>
<button {{action "submit"}}>Guardar</button>
</div>
</script>
code
App.NewElementView = Ember.View.extend
tagName: 'li'
click: (event) ->
#insertElement()
insertElement: ->
view = Ember.View.create
templateName: "my-custom-view"
container: #container
dom_id: "foo"
view.appendTo("#container")
Here a working example http://emberjs.jsbin.com/rapepepogi/17/edit?html,js,output

when bootstrap date picker date select some action call in ember js controller

I am new to ember, developing Filtering by date functionality using ember js.
handle bars:
<div class="input-group date" data-behavior="ActiveRock.filterDatePicker" data-date-before-field="#filter_end_date">
<input type="text" class="form-control" id="filter_start_date" {{action filterPortfolios}}/>
<span class="input-group-addon">
<span class="glyphicon glyphicon-calendar"></span>
</span>
</div>
Behaviour:
$ ->
ActiveRock.datePicker = (el) ->
el.datepicker(
format: 'yyyy/mm/dd'
autoclose: true
).on('show', (e) ->
$('.datepicker').css('z-index', '1151')
true
).on('hide', (e) ->
logic
return false
true
)
controller action: filterPortfolios
included bootstrap datepicker
but it is not working, please suggest any solution.
Thanks,
Prasad.
In behavior I written like taht
$(function() {
return ExamplePicker.filterDatePicker = function(el) {
return el.datepicker({
format: 'yyyy/mm/dd',
autoclose: true
}).on('changeDate', function(e) {
var controller;
controller = App.__container__.lookup("controller:<controller_name>");
controller.send("<action_name>");
return true;
});
};
});

How to add text input to dropzone upload

I'd like to allow users to submit a title for each file that is dragged into Dropzone that will be inputted into a text input. But i don't know how to add it. Everyone can help me?
This is my html code code
<form id="my-awesome-dropzone" class="dropzone">
<div class="dropzone-previews"></div> <!-- this is were the previews should be shown. -->
<!-- Now setup your input fields -->
<input type="email" name="username" id="username" />
<input type="password" name="password" id="password" />
<button type="submit">Submit data and files!</button>
</form>
And this is my script code
<script>
Dropzone.options.myAwesomeDropzone = { // The camelized version of the ID of the form element
// The configuration we've talked about above
url: "upload.php",
autoProcessQueue: false,
uploadMultiple: true,
parallelUploads: 100,
maxFiles: 100,
maxFilesize:10,//MB
// The setting up of the dropzone
init: function() {
var myDropzone = this;
// First change the button to actually tell Dropzone to process the queue.
this.element.querySelector("button[type=submit]").addEventListener("click", function(e) {
// Make sure that the form isn't actually being sent.
e.preventDefault();
e.stopPropagation();
myDropzone.processQueue();
});
// Listen to the sendingmultiple event. In this case, it's the sendingmultiple event instead
// of the sending event because uploadMultiple is set to true.
this.on("sendingmultiple", function() {
// Gets triggered when the form is actually being sent.
// Hide the success button or the complete form.
});
this.on("successmultiple", function(files, response) {
// Gets triggered when the files have successfully been sent.
// Redirect user or notify of success.
});
this.on("errormultiple", function(files, response) {
// Gets triggered when there was an error sending the files.
// Maybe show form again, and notify user of error
});
},
accept: function (file, done) {
//maybe do something here for showing a dialog or adding the fields to the preview?
},
addRemoveLinks: true
}
</script>
You can actually provide a template for Dropzone to render the image preview as well as any extra fields. In your case, I would suggest taking the default template or making your own, and simply adding the input field there:
<div class="dz-preview dz-file-preview">
<div class="dz-image"><img data-dz-thumbnail /></div>
<div class="dz-details">
<div class="dz-size"><span data-dz-size></span></div>
<div class="dz-filename"><span data-dz-name></span></div>
</div>
<div class="dz-progress"><span class="dz-upload" data-dz-uploadprogress></span></div>
<div class="dz-error-message"><span data-dz-errormessage></span></div>
<input type="text" placeholder="Title">
</div>
The full default preview template can be found in the source code of dropzone.js.
Then you can simply pass your custom template to Dropzone as a string for the previewTemplate key of the option parameters. For example:
var myDropzone = new Dropzone('#yourId', {
previewTemplate: "..."
});
As long as your element is a form, Dropzone will automatically include all inputs in the xhr request parameters.
I am doing something fairly similar. I accomplished it by just adding a modal dialog with jquery that opens when a file is added. Hope it helps.
this.on("addedfile", function() {
$("#dialog-form").dialog("open");
});
In my answer, substitute your "title" field for my "description" field.
Add input text or textarea to the preview template. For example:
<div class="table table-striped files" id="previews">
<div id="template" class="file-row">
<!-- This is used as the file preview template -->
<div>
<span class="preview"><img data-dz-thumbnail /></span>
</div>
<div>
<p class="name" data-dz-name></p>
<input class="text" type="text" name="description" id="description" placeholder="Searchable Description">
</div> ... etc.
</div>
</div>
Then in the sending function, append the associated data:
myDropzone.on("sending", function(file, xhr, formData) {
// Get and pass description field data
var str = file.previewElement.querySelector("#description").value;
formData.append("description", str);
...
});
Finally, in the processing script that does the actual upload, receive the data from the POST:
$description = (isset($_POST['description']) && ($_POST['description'] <> 'undefined')) ? $_POST['description'] : '';
You may now store your description (or title or what have you) in a Database etc.
Hope this works for you. It was a son-of-a-gun to figure out.
This one is kind of hidden in the docs but the place to add additional data is in the "sending" event. The sending event is called just before each file is sent and gets the xhr object and the formData objects as second and third parameters, so you can modify them.
So basically you'll want to add those two additional params and then append the additional data inside "sending" function or in your case "sendingmultiple". You can use jQuery or just plain js to get the values. So it should look something like:
this.on("sendingmultiple", function(file, xhr, formData) {
//Add additional data to the upload
formData.append('username', $('#username').val());
formData.append('password', $('#password').val());
});
Here is my solution:
Dropzone.autoDiscover = false;
var myDropzone = new Dropzone("#myDropzone", {
url: 'yourUploader.php',
init: function () {
this.on(
"addedfile", function(file) {
caption = file.caption == undefined ? "" : file.caption;
file._captionLabel = Dropzone.createElement("<p>File Info:</p>")
file._captionBox = Dropzone.createElement("<input id='"+file.filename+"' type='text' name='caption' value="+caption+" >");
file.previewElement.appendChild(file._captionLabel);
file.previewElement.appendChild(file._captionBox);
}),
this.on(
"sending", function(file, xhr, formData){
formData.append('yourPostName',file._captionBox.value);
})
}
});
yourUploader.php :
<?php
// Your Dropzone file named
$myfileinfo = $_POST['yourPostName'];
// And your files in $_FILES
?>
$("#my-awesome-dropzone").dropzone({
url: "Enter your url",
uploadMultiple: true,
autoProcessQueue: false,
init: function () {
let totalFiles = 0,
completeFiles = 0;
this.on("addedfile", function (file) {
totalFiles += 1;
localStorage.setItem('totalItem',totalFiles);
caption = file.caption == undefined ? "" : file.caption;
file._captionLabel = Dropzone.createElement("<p>File Info:</p>")
file._captionBox = Dropzone.createElement("<textarea rows='4' cols='15' id='"+file.filename+"' name='caption' value="+caption+" ></textarea>");
file.previewElement.appendChild(file._captionLabel);
file.previewElement.appendChild(file._captionBox);
// this.autoProcessQueue = true;
});
document.getElementById("submit-all").addEventListener("click", function(e) {
// Make sure that the form isn't actually being sent.
const myDropzone = Dropzone.forElement(".dropzone");
myDropzone.processQueue();
});
this.on("sending", function(file, xhr, formData){
console.log('total files is '+localStorage.getItem('totalItem'));
formData.append('description[]',file._captionBox.value);
})
}
});
For those who want to keep the automatic and send datas (like an ID or something that does not depend on the user) you can just add a setTimeout to "addedfile":
myDropzone.on("addedfile", function(file) {
setTimeout(function(){
myDropzone.processQueue();
}, 10);
});
Well I found a solution for me and so I am going to write it down in the hope it might help other people also. The basic approach is to have an new input in the preview container and setting it via the css class if the file data is incoming by succeeding upload process or at init from existing files.
You have to integrate the following code in your one.. I just skipped some lines which might necessary for let it work.
photowolke = {
render_file:function(file)
{
caption = file.title == undefined ? "" : file.title;
file.previewElement.getElementsByClassName("title")[0].value = caption;
//change the name of the element even for sending with post later
file.previewElement.getElementsByClassName("title")[0].id = file.id + '_title';
file.previewElement.getElementsByClassName("title")[0].name = file.id + '_title';
},
init: function() {
$(document).ready(function() {
var previewNode = document.querySelector("#template");
previewNode.id = "";
var previewTemplate = previewNode.parentNode.innerHTML;
previewNode.parentNode.removeChild(previewNode);
photowolke.myDropzone = new Dropzone("div#files_upload", {
init: function() {
thisDropzone = this;
this.on("success", function(file, responseText) {
//just copy the title from the response of the server
file.title=responseText.photo_title;
//and call with the "new" file the renderer function
photowolke.render_file(file);
});
this.on("addedfile", function(file) {
photowolke.render_file(file);
});
},
previewTemplate: previewTemplate,
});
//this is for loading from a local json to show existing files
$.each(photowolke.arr_photos, function(key, value) {
var mockFile = {
name: value.name,
size: value.size,
title: value.title,
id: value.id,
owner_id: value.owner_id
};
photowolke.myDropzone.emit("addedfile", mockFile);
// And optionally show the thumbnail of the file:
photowolke.myDropzone.emit("thumbnail", mockFile, value.path);
// Make sure that there is no progress bar, etc...
photowolke.myDropzone.emit("complete", mockFile);
});
});
},
};
And there is my template for the preview:
<div class="dropzone-previews" id="files_upload" name="files_upload">
<div id="template" class="file-row">
<!-- This is used as the file preview template -->
<div>
<span class="preview"><img data-dz-thumbnail width="150" /></span>
</div>
<div>
<input type="text" data-dz-title class="title" placeholder="title"/>
<p class="name" data-dz-name></p><p class="size" data-dz-size></p>
<strong class="error text-danger" data-dz-errormessage></strong>
</div>
<div>
<div class="progress progress-striped active" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0">
<div class="progress-bar progress-bar-success" style="width:0%;" data-dz-uploadprogress></div>
</div>
</div>
</div>

Ajax form submission, files not getting submitted

I am trying to implement AJAX form submission for my Django forms.
The files are getting submitted without AJAX, so the logic at the serverside seems to be working. and with ajax, the rest of the values except the files get submitted.
Here is the code that I am implementing,
AJAX form Submission
(function() {
// using jQuery
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie != '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) == (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
var csrftoken = getCookie('csrftoken');
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
crossDomain: false, // obviates need for sameOrigin test
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type)) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
})();
jquery
$('#save-form').live('submit', function(event) { // catch the form's submit event
event.preventDefault();
$.ajax({ // create an AJAX call...
data: $(this).serialize(), // get the form data
type: $(this).attr('method'), // GET or POST
url: '/save/', // the file to call
success: function(response) { // on success..
$('#modalsave-form').html(response); // update the DIV
}
});
return false;
});
HTML Form
<form class="form-horizontal" id="save-form" enctype="multipart/form-data" method="post" action="/save/">
<div class="control-group">
<label class="control-label" for="id_body">Write Something</label>
<div class="controls">
<textarea class="typeaheadfun" id="id_body" rows="3" cols="100" name="body" placeholder="Scribble Body" style="width: 455px;"></textarea>
</div>
</div>
<div class="control-group">
<label class="control-label" for="id_media">Add a File</label>
<div class="controls">
<input type="file" name="media" id="id_media"/>
</div>
</div>
<hr>
<input class="btn btn-primary pull-right" type="submit" value="Post!" />
<br>
{% csrf_token %}
</form>
When you submit an HTML form it usually sends form's data to the server using either GET or POST data HTML headers. When however you need to send binary data or attached file(s) to the server efficiently, HTML as part of it's spec has a different method for sending such data. enctype attribute of <form> tag specifies using which method should the browser send the data to the server. To send files, multipart/form-data is widely used encoding method.
When you try to send form without ajax, browser sends file data to the server using multipart/form-data encoding however when you submit the form using ajax you do the following:
data: $(this).serialize()
That step does not encode data the same way as server expects the data hence your ajax does not work.
To make it work, instead of manually submitting form's data, you should submit the whole form using ajax. Doing it manually is tricky plus there are plugins which do that already. One such plugin is jQuery Form Plugin. It allows to submit the whole form using ajax. The following is js code which should give you an idea on how to integrate it with your setup:
$('#save-form').live('submit', function(event) {
event.preventDefault();
$(this).ajaxSubmit({
url: '/save/', // the file to call
success: function(response) {
$('#modalsave-form').html(response);
}
});
return false;
});
Another option is to use the FormData interface that absolves the need for a plugin
https://developer.mozilla.org/en-US/docs/Web/API/FormData
Sample Code: (Adapt to suit your needs)
`
$('#fupload').click(function(){
var xhr = new XMLHttpRequest();
var token = $('input[name="csrfmiddlewaretoken"]').prop('value');
$.ajaxSetup({
headers: { "X-CSRFToken": token }
});
var formData = new FormData($('form')[0]);
formData.append('file',xhr.file);
$.ajax({
url: '/myurl/', //server script to process data
type: 'POST',
xhr: function() { // custom xhr
myXhr = xhr;
//if(xhr.upload){ // check if upload property exists
// xhr.upload.addEventListener('progress',progressHandlingFunction, false);
// for handling the progress of the upload
//}
return xhr;
},
// Form data
data: formData,
//Ajax events
success: function(server_response){
$( '#path' ).val("Success");
},
error: function(jqXHR, textStatus, errorThrown ){
$( '#path' ).val(errorThrown);
},
//Options to tell JQuery not to process data or worry about content-type
cache: false,
contentType: false,
processData: false
});
});
`