Jquery/Dropzone.js Get the current index of an added image - javascript

I am building a custom Dropzone.js: http://www.dropzonejs.com/ layout. The upload is working well. I am wanting to save additional data in the form that the Dropzone is in for a specific post.
I need to index the array so that all the data is posted is relevant in the array.
The 'previewTemplate' allows for strings only - no function.
eg: lead_image[ INDEX HERE ][filename]
uploader.dropzone({
url: "/admin/upload",
acceptedFiles: 'image/*',
thumbnailWidth: 80,
thumbnailHeight: 80,
parallelUploads: 20,
autoProcessQueue: true, // Make sure the files aren't queued until manually added
clickable: ".fileinput-button", // Define the element that should be used as click trigger to select files.
previewsContainer: "#previews", // Define the container to display the previews
init: function() {
this.on("addedfile", function(file) {
var index = $('li.image').length;
});
},
previewTemplate: '<li class="image row dd-item">' +
'<div class="col-sm-1 dd-handle">' +
'<span class="preview">' +
'<img data-dz-thumbnail />' +
'</span>' +
'</div>' +
'<div class="col-sm-8">' +
'<p><span class="name" data-dz-name></span> | <span class="size" data-dz-size></span></p>' +
'<input type="hidden" class="form-control" name="lead_image[ INDEX HERE ][filename]" data-dz-name/>' +
'<input type="text" class="form-control" name="lead_image[ INDEX HERE ][title]" value="" placeholder="Title" />' +
'<input type="text" class="form-control" name="lead_image[ INDEX HERE ][alt]" value="" placeholder="Alt Tag" />' +
'<input type="text" class="form-control" name="lead_image[ INDEX HERE ][caption]" value="" placeholder="Caption" />' +
'<input type="text" class="form-control" name="lead_image[ INDEX HERE ][sort]" value="" placeholder="Sort Order" />' +
'<strong class="error text-danger" data-dz-errormessage></strong>' +
'</div>' +
'<div class="col-sm-2">' +
'<button data-dz-remove class="btn btn-danger delete"><i class="glyphicon glyphicon-trash"></i><span>Delete</span></button>' +
'</div>' +
'</li>',
});
I am having difficulty passing the template the index of the current item as these items are passed through later.
Has anyone dealt with this or can see a solution? I am currently trying to inject the file name as the index as a solution, but this isn't the best way to go in my mind.
Thanks in advance for taking the time to help.

bI sorted this in the end.
init: function() {
this.on("success", function(file, responseText) {
console.log(responseText);
// Create the hidden fields
// Created_at
file.createdat = Dropzone.createElement("<input type=\"hidden\" class=\"form-control input-sm\" name=\"" + this.options.inputName + "[" + responseText.id + "][created_at]\" value=\"" + responseText.created_at + "\" />");
file.previewElement.appendChild(file.createdat);
}
}
On the init function, you are basically waiting to hear back from Dropzone of the successful uploaded. So, depending on your server side implementation, you can pass back any data you want about the file. In my case, I stored it in the DB and returned the row's info.
From there, to save that information in in the current post, I just created some hidden fields to store the data and then repeated the above for each hidden field I wanted. You can of course add other non-hidden fields for things like alt tags, titles or anything you like.
The index I was after in the the responseText: this.options.inputName + "[" + responseText.id + "][created_at]
Hope it helps.
As a side note, you can also do the same thing when loading files that have been stored on the server that you want to retrieve for this specific post. Just Google mockfile and dropzone and you should find a million results helping you. Its the same principle.

Related

URL Encoding : Javascript

I have a javascript capturing signatures and data.
The " are getting lost/cutoff and not conserving. I assume this is a URLEncoding issue.
This is the original.
'<input type="hidden" name="rvnotes" value="' + rvnotes + '"/>' +
And I have tried this, but still no luck. Any idea how to URL Encode the Javascript submission.
'<input type="hidden" name="rvnotes" value="' + encodeURIComponent(rvnotes) + '"/>' +
The trick must be done in <form>.
<form enctype="application/x-www-form-urlencoded" ...>

Calculating sum of products using Javascript

I have list of products for users to select. When user selects a product, the price is displayed and the user enters the quantity to calculate the total price for all selected products.
Now with my code, the total price for the first selected product appears the same for all other products selected afterwards. i.e
If user selects Fifa and PRO the total price for FIFA appears for PRO as below
Item : Fifa
Price : 100eu
Quantity : 4
Total price : 400eu
Item : PRO
Price: 50eu
Quantity: 1
Total Price: 400eu
But this is what i am looking to have
Item : Fifa
Price : 100eu
Quantity : 4
Total price : 400eu
Item : PRO
Price: 50eu
Quantity: 1
Total Price: 50eu
Total Order Price = 400eu + 50eu = 450eu
JS
public selectGame(game){
$(".gameshop").append(
'<p id="name">Item: ' + game.name + '</p>'+
'<p name="price" id="price" data-price="'+game.price+'"> Price : ' + game.price + '</p>'+
'<input type="text" onKeyUp="final()" id="quantity" name="quantity" />' +
'<p id="final_price">Total Price $:<span></span></p>').appendTo('form')
}
function final()
{
a = Number($('#quantity').val());
b = Number($('#price').data("price"));
c = a * b;
$("#final_price span").text(c);
}
HTML
<form class="form-horizontal" method="post">
#foreach ($errors->all() as $error)
<p class="alert alert-danger">{{ $error }}</p>
#endforeach
#if (session('status'))
<div class="alert alert-success">
{{ session('status') }}
</div>
#endif
{!! csrf_field() !!}
<fieldset>
<div class="panel label_container">
<input onclick="return selectGame(this)" type="checkbox" id="{!! $game->id !!}" " />
<label class="mylabel" > </label>
</div>
<legend>Games</legend>
<div class="gameshop" id="gameshop">
</div>
</div>
</fieldset>
</form>
Update
function selectGame(game)
{
$('.gameshop').append(
'<div class="item">'+
'<p class="name"> Item: ' + game.name + '</p>'+
'<p class="price" data-price="'+game.price+'"> Price : ' + game.price + '</p>'+
'<input type="text" class="quantity" name="quantity" />'+
'<p class="total">Total Price $:<span></span></p>'+
'</div>'
)
$('.gameshop').on('keyup','.quantity',function()
{
var a = Number($(this).val());
var b = Number($(this).closest('div').find('.price').data('price'));
alert(b);
});
}
There are a few steps to correct this, since there are a couple of simultaneous problems. Namely (1) you're re-using id values in your HTML and (2) you're trying to get and update values globally on the page when you want to get do so relatively to the element invoking the event.
First, replace all of your ids in your dynamic HTML string with class values instead. This will prevent the HTML from being invalid by re-using id values. Something like:
'<p class="name">Item: ' + game.name + '</p>'+
//... and so on
Also, remove your onKeyUp inline handler from the <input> element:
'<input type="text" class="quantity" name="quantity" />'+
Next, bind your keyup event using jQuery and event delegation. Have a single declared event handler on a parent element to handle the event:
$('.gameshop').on('keyup', '.quantity', function () {
//...
});
This event handler replaces your final() function. This should take care of the multiple-id problem, but now inside this event handler we need to navigate the DOM to find the elements you're looking for.
First, wrap your dynamic elements in a container of some sort. Any <div> will do. Something like:
'<div class="product">'+ // <--- here
'<p class="name">Item: ' + game.name + '</p>'+
//...
'<p class="final_price">Total Price $:<span></span></p>'+
'</div>' // <--- and here
Then we can use that container as a stopping point to navigate up and down the DOM to find the target elements. First, we can find the "quantity" from the event-throwing element itself. So instead of this:
a = Number($('#quantity').val());
We can just use the element itself:
var a = Number($(this).val());
For other values, it's a neighboring element. This would involve navigating up and down the DOM to find that element. So instead of this:
b = Number($('#price').data("price"));
You can do something like this:
var b = Number($(this).closest('div').find('.price').data('price'));
Notice how it starts from the element throwing the event (this), navigates up to the container (<div>), then back down to the target element (.price). This should identify the specific element you want to find, relative to the one throwing the event.
Repeat these same corrections for your other elements, selectors, etc.
There could very well be other issues here, but these appear to be the main structural/logical problems you're encountering. (Another potential problem could be that strange combined use of .append() and .appendTo(), I'm not really sure what that's accomplishing. You should only need one of those.)
You are appending dynamically tags with same ids, consider adding something to the id such
id="xxx"+"_"+i
being i an index

jquery Datatables multiple tables populated from partial view - 'Cannot Reinitialize' error

I have an MVC project where I'm using jquery DataTables 1.10.2. Within my project's pages I often have multiple places where I need to reuse a partial view, which contains a self-contained jquery DataTable instance, initialization, and handlers. As the partial view is being built I uniquely name each DT instance using a GUID, including all other buttons, etc, so each should be able to exist in its own world, not caring about those around it. Or so I thought... I've read quite a bit on this issue and I can't seem to determine why this is happening. From what I'm doing I don't believe that I'm attempting to change/reinitialize an existing DT instance. When I only have a single one of these DT partial views everything is great. Any thoughts?
I have 3 of these partial views that must reside on the page, and I always get this kinda message:
Also, only the last instance actually shows any records, 3x what it's supposed to display, and all the others are just blank (not even the no data message).
1. Here's how I create my raw HTML table within my partial view, where I have a unique identifier for the table:
2. Here's an example how the calling view requests the partial view in question:
I pass a unique identifier (GUID), along with my data via a ViewModel into the partial view. All standard MVC kinda stuff, and is working fine.
3. Here's my partial view initialization of the DataTable with razor injected into the javascript creating a unique HTML table ID for each DT to use, along with a unique DT global object variable (c#unique), which when populated will look something like this: c6e201ac10b4a4a6a987878c7b2390fa4. I shouldn't need to reinitialize anything, despite DT telling me. Each version of the DataTable partial view should have all its variables (c#unique, rows#unique, etc.) to be unique. The existingData variable is set here, which is passed in via the ViewModel:
c#(unique) = $('##(unique)phones').DataTable(
{
"data" : existingData
, "responsive": true
, "searching" : false
, "paging": false
, "order": 0
, "createdRow" : function (row, data, index){
$(row).attr("data-id", index);
rows#(unique)++;
}
, "columns": [
{ "data": "Id"
, "visible" : false
}
, { "data": "PhoneTypeID", "title": "Phone Type",
render : function (data, type, row, meta) {
// Renders combination of select element, with exisitng value correctly selected and validation control
var $clone = $select.clone();
$clone.attr('name', 'Phones[' + rows#(unique) + '].PhoneTypeID' ); // changing the phone collection name for serialization
$clone.find('option[value="' + data + '"]').attr('selected','selected'); // attempting to match existing data
$clone.attr('data-val', 'true' ); // adding validation
$clone.attr('data-val-required', 'Phone Type Required' ); // adding error message
var validation = ' <div><span class="field-validation-valid text-danger" data-valmsg-for="Phones[' + rows#(unique) + '].PhoneTypeID" data-valmsg-replace="true" </span></div>';
var selectctl = $clone.wrap('<div></div>').parent().html();
// combines both the select control and the validation span element
return selectctl.concat(validation);
}}
, { "data": "PhoneNumber", "title": "Phone Number",
render : function (data, type, row) {
// Renders combination of phone number text box, with exisitng value correctly selected and validation control
var phoneDetail = '<div><input class="form-group" name="Phones[' + rows#(unique) + '].PhoneNumber" placeholder="Number" type="tel" pattern="\d{3}[\-]\d{3}[\-]\d{4}" value="' + data + '"'
+ ' data-val="true" data-val-required="Phone Required" />'
+ ' <input type="hidden" name="Phones[' + rows#(unique) + '].Id" value="' + row["Id"] + '" />'
+ ' <span class="field-validation-valid text-danger" data-valmsg-for="Phones[' + rows#(unique) + '].PhoneNumber" data-valmsg-replace="true" /></div>';
return phoneDetail;
}}
, { "data" : "Id",
render : function (data,type,row,meta){
var deleteBtn = '<a class="btn btn-warning removeSelected" href="#">Delete</a>';
return deleteBtn;
}
}
]
});
I'm rendering some columns to have a select element (PhoneTypeId), a text box (PhoneNumber) and a button for deleting. The select element is setup using some code that creates a $select element (not included here) that's then cloned within the rendering column to match any existing data. All my element names use this notation (SomeName[index].PropertyName) so the serializer will understand when the page is posted to my collections, etc.
Here's a working example of what it looks like, including when the row is selected and displays the delete button. Not fully styled yet, as I can't seem to have more than 1 on a page! Any help is appreciated!
The code itself wasn't the problem. To keep my doc.ready event clean and tidy I used a call to the method LoadDataTable(). When two or more of these partial views were loaded and doc.ready was finally called, there were multiple LoadDataTable methods, each pointing to an already existing instance of a DataTable. This is why I kept getting that initialize error. My Solution: Either create a dynamically named LoadDataTable method (using razor), or just put everything directly inside the partial's doc.ready method. Working fine now!
What I could see is that you weren't trying to destroy an existing table. Looking at the following in your post:
c#(unique) = $('##(unique)phones').DataTable(
{
"data" : existingData
, "responsive": true
, "searching" : false
, "paging": false
, "order": 0
, "createdRow" : function (row, data, index){
$(row).attr("data-id", index);
rows#(unique)++;
}
, "columns": [
{ "data": "Id"
, "visible" : false
}
, { "data": "PhoneTypeID", "title": "Phone Type",
render : function (data, type, row, meta) {
// Renders combination of select element, with exisitng value correctly selected and validation control
var $clone = $select.clone();
$clone.attr('name', 'Phones[' + rows#(unique) + '].PhoneTypeID' ); // changing the phone collection name for serialization
$clone.find('option[value="' + data + '"]').attr('selected','selected'); // attempting to match existing data
$clone.attr('data-val', 'true' ); // adding validation
$clone.attr('data-val-required', 'Phone Type Required' ); // adding error message
var validation = ' <div><span class="field-validation-valid text-danger" data-valmsg-for="Phones[' + rows#(unique) + '].PhoneTypeID" data-valmsg-replace="true" </span></div>';
var selectctl = $clone.wrap('<div></div>').parent().html();
// combines both the select control and the validation span element
return selectctl.concat(validation);
}}
, { "data": "PhoneNumber", "title": "Phone Number",
render : function (data, type, row) {
// Renders combination of phone number text box, with exisitng value correctly selected and validation control
var phoneDetail = '<div><input class="form-group" name="Phones[' + rows#(unique) + '].PhoneNumber" placeholder="Number" type="tel" pattern="\d{3}[\-]\d{3}[\-]\d{4}" value="' + data + '"'
+ ' data-val="true" data-val-required="Phone Required" />'
+ ' <input type="hidden" name="Phones[' + rows#(unique) + '].Id" value="' + row["Id"] + '" />'
+ ' <span class="field-validation-valid text-danger" data-valmsg-for="Phones[' + rows#(unique) + '].PhoneNumber" data-valmsg-replace="true" /></div>';
return phoneDetail;
}}
, { "data" : "Id",
render : function (data,type,row,meta){
var deleteBtn = '<a class="btn btn-warning removeSelected" href="#">Delete</a>';
return deleteBtn;
}
}
]
});
You need to add "destroy", true. Let it look like the following:
c#(unique) = $('##(unique)phones').DataTable(
{
"destroy" : true
"data" : existingData
, "responsive": true
, "searching" : false
, "paging": false
, "order": 0
, "createdRow" : function (row, data, index){
$(row).attr("data-id", index);
rows#(unique)++;
}
, "columns": [
{ "data": "Id"
, "visible" : false
}
, { "data": "PhoneTypeID", "title": "Phone Type",
render : function (data, type, row, meta) {
// Renders combination of select element, with exisitng value correctly selected and validation control
var $clone = $select.clone();
$clone.attr('name', 'Phones[' + rows#(unique) + '].PhoneTypeID' ); // changing the phone collection name for serialization
$clone.find('option[value="' + data + '"]').attr('selected','selected'); // attempting to match existing data
$clone.attr('data-val', 'true' ); // adding validation
$clone.attr('data-val-required', 'Phone Type Required' ); // adding error message
var validation = ' <div><span class="field-validation-valid text-danger" data-valmsg-for="Phones[' + rows#(unique) + '].PhoneTypeID" data-valmsg-replace="true" </span></div>';
var selectctl = $clone.wrap('<div></div>').parent().html();
// combines both the select control and the validation span element
return selectctl.concat(validation);
}}
, { "data": "PhoneNumber", "title": "Phone Number",
render : function (data, type, row) {
// Renders combination of phone number text box, with exisitng value correctly selected and validation control
var phoneDetail = '<div><input class="form-group" name="Phones[' + rows#(unique) + '].PhoneNumber" placeholder="Number" type="tel" pattern="\d{3}[\-]\d{3}[\-]\d{4}" value="' + data + '"'
+ ' data-val="true" data-val-required="Phone Required" />'
+ ' <input type="hidden" name="Phones[' + rows#(unique) + '].Id" value="' + row["Id"] + '" />'
+ ' <span class="field-validation-valid text-danger" data-valmsg-for="Phones[' + rows#(unique) + '].PhoneNumber" data-valmsg-replace="true" /></div>';
return phoneDetail;
}}
, { "data" : "Id",
render : function (data,type,row,meta){
var deleteBtn = '<a class="btn btn-warning removeSelected" href="#">Delete</a>';
return deleteBtn;
}
}
]
});

Cancel a form to be submitted, do not change the data of the entity

I have a div
<div id="updateChoice%s" class="text-center"></div>
which shows a the following upon a "updateText" button is clicked
function updateText(urlsafe) {
document.getElementById("updateChoice"+urlsafe).innerHTML +=
'<br><br><form id="dynForm" action="/updateText" method="post" >' +
'<textarea name="newContent" rows="5" cols="80"></textarea>' +
'<input type="hidden" name="update" value=' + urlsafe + '>' + '<br><br>' +
'<input class="choice" type="submit" value="Submit"></input> <button class="choice" onclick="cancelUpdate('+ urlsafe +')">Cancel</button>' +
'</form>';
}
I want to cancel the updating of the text but it doesn't work unless "newContent" is empty, here is /updateText file and cancelUpdate(urlsafe)
/updateText:
class UpdateText(webapp2.RequestHandler):
def post(self):
greeting_key = ndb.Key(urlsafe=self.request.get('update'))
event = greeting_key.get();
if(self.request.get('newContent') != ''):
event.content = self.request.get('newContent');
event.put();
self.redirect('/events');
cancelUpdate(urlsafe):
function cancelUpdate(urlsafe) {
document.getElementByName("newContent").innerHTML="";
document.getElementById("dynForm").submit();
}
any ideas?
The /updateText handler remains on not updating the text if upon submission it is empty, so do not change anything:
In the cancelUpdate(urlsafe) function, use this aproach:
function cancelUpdate(urlsafe) {
document.getElementById("updateChoice"+urlsafe).innerHTML = "";
}
Add \' to the parameter urlsafe as you pass it and not ". So here is correct javascript function call to div#updateChoice%s is:
function updateText(urlsafe) {
document.getElementById("updateChoice"+urlsafe).innerHTML =
'<br><br><form id="dynForm" action="/updateText" method="post" >' +
'<textarea name="newContent" rows="5" cols="80"></textarea>' +
'<input type="hidden" name="update" value=' + urlsafe + '>' + '<br><br>' +
'<input class="choice" type="submit" value="Submit"></input><button type="button" class="choice" onClick="cancelUpdate(\''+ urlsafe +'\')">Cancel</button>' +
'</form>';
}
Your question is very difficult to understand (What do you mean by "cancel the updating of the text"? What did you expect to happen? What exactly "doesn't work"?).
Also, there are multiple issues with the code you provided (none of which have to do anything with GAE, Python or webapp2), here are a few that might be helpful to resolve your issue:
1) Your cancelUpdate function accepts a urlsafe parameter but is not using it.
2) In your cancelUpdate function you're using a non-existing function getElementByName, you probably meant to use its plural version getElementsByName()
3)
On the same document.getElementByName("newContent").innerHTML=""; line you are retreiving an element with the name newContent which is a <textarea> element and are attempting to empty its innerHTML property, but a <textarea> doesn't have one. If you want to empty a <textarea>'s contents - you need to do document.getElementByName("newContent").value=""; instead.
Since your cancelUpdate function has an unused parameter urlsafe and although it's not clear what your issue is but since in your updateText function you are creating an element with id="updateChoice"+urlsafe and assuming that when you hit cancel - you also want to destroy that form, then your cancelUpdate would look as simple as this:
function cancelUpdate(urlsafe) {
document.getElementById("updateChoice"+urlsafe).innerHTML = "";
}
4)
Your "Cancel" button doesn't have a type specified which means it will default to submit even when you don't want to submit the form so you need to add type="button" to prevent the submission.
You are calling document.getElementById("dynForm").submit(); in your cancelUpdate function which in the combination with the previous issue will submit your form twice.

Converting pairs of input elements into json

I have a simple ui which has a link that says "add item". When this is clicked, a pair of input boxes appears below it. If it is clicked again, yet another pair appears. I'm trying to think of the best way to generate these elements and turn it into some sort of json array of key value pairs (the first input element in each pair being the key and the second input element being the value).
Right now I just have a counter and I generate the ids using it, such as (in the click event of the "add item" link):
$('#features').append('<input id="feature-name-' + self.featureCount + '" type="text" name="asdf" /><a class="delete-feature" data-id="' + self.featureCount + '">Delete</a><input id="feature-description-' + self.featureCount + '" type="text" name="asdf" />');
I don't know what to use as the "name" attributes in order to make it easy to create a json array from them.
you can do something like this without using id attributes.
$('#features').append('<div><input type="text" />
<a class="delete-feature" data-id="' + self.featureCount + '">Delete</a><input type="text" /></div>');
And your javascript,
var yourArray=[];
$('#yourButton').click(function(){
$('#features div').each(function(){
var div=$(this);
var k=$('input:first',div).val();
var v=$('input:first',div).next().val();
yourArray.push({key:k, value: v});
});
});
It doesn't matter what you use for a name attribute, so long as there name and description names are different. Let's say that these elements are all appended to a form with the id myform. Give each pair its own wrapper object. Here, I've used a div, but a fieldset is equally appropriate.
$('#features').append(
'<div class="feature-div">
'<input id="feature-name-' + self.featureCount + '" type="text" name="asdf" />' +
'<a class="delete-feature" data-id="' + self.featureCount + '">Delete</a>' +
'<input id="featurena-description-' + self.featureCount + '" type="text" name="asdf" />' +
'</div>');
Now, it's possible to extract each pair sensibly:
var myarray = [];
$('#myform .feature-div').each(function(i, v) {
myarray.push([
$('input[name=name]', v).val(), $('input[name=description]', v).val()]);
});
Or however you want the data to be presented.

Categories