I am using a multiple file upload field <input name="filesToUpload" id="filesToUpload" type="file" multiple /> in my app.
What I want to accomplish is to list the files the users chose and than allow them to delete any of them in the list.
At the end, when the form is submitted, I send the whole data via AJAX, as binary, using the FormData object.
It all works great, except for the delete part.
I know that the FileList attribute is read-only, so what I did was to distribute the files as values of hidden input fields, appended to each of the li where I list the file names. So if the user removes a li item, the hidden input field is gone with it, and at the end, I collect all remaining by appending them to the FormData object.
Problem is, every attempt I made to assign the files as values to the hidden inputs gave me weird results.
My code is something like this:
listFiles : function () {
var file, files, filesList, filesLength, read;
files = this.files;
filesList = $('.files');
filesLength = files.length;
// Clear the list
filesList.html('');
for ( var i = 0; i < filesLength; i++ ) {
file = files[i];
// This is to read the content of the file
read=new FileReader();
read.readAsBinaryString( file );
// When reading is finished
read.onloadend = function() {
filesList.append(
'<li>' +
'<span class="fileName">' + file.name + '</span>' +
'x' +
'<input type="hidden" name="file[]" value="' + read.result +'"/>' +
'</li>');
}
}
}
I just get the data from the last file, also, the DOM is broken since the data gets printed all over the place.
Demo here => http://jsfiddle.net/zKyXC/
I have tried various ways to implement the method described above ( assign each separate file to the value of an input[type="hidden"] field in order to allow file delete functionality ) but non of them were successful.
At this moment, I do not know if this is this possible to be done at all.
However, I did manege to solve the problem with an alternative solution. Here it is in case someone else finds it useful.
Instead of using input[type="hidden"] I used a global array where I stored the files upon receiving them. Then I remove items from that array the standard way you would remove objects from an array. At the end I append each item to the formData object and send it to the server.
I create and fill the global array like this:
globals.files =[].slice.call( this.files );
i remove from it like this:
$.each( files, function( index, val ) {
if ( this.name === fileText ) {
globals.files.splice( index, 1 );
}
});
Note : fileText is where I store the name of the item to be deleted.
And at the end I append it to formData :
var formData = new FormData();
$.each( files, function( ind, val ) {
formData.append( 'files[]', this );
});
And send this as the data property of a standard jQuery ajax call.
if I am not wrong, only file with quotation mark " goes wrong, if you do not escape it, value will be cut off at the first occurence of " and the rest part will be shown as html, so what you need is
read.result.replace(/"/g, '"');
Related
I've checked out some of the other similar questions but they aren't doing exactly what I'm trying to do. I'm ajaxing a php page to echo the contents of a folder on my server. Right now, I have it listing the files line by line. I would simply like to take the value of each line and add it to a select box.
If I can just come up with a way in javascript to run a loop for each line found from this php page, I can add the option to the select myself. Any idea of how to accomplish this? Everything I find online is for a different scenario and I can't find anything that'll work. Thanks
Edit: This is the closest I've gotten
var files = msg.split(" ");
$.each(files, function(index, value) {
var x = document.getElementById("Emulators");
var option = document.createElement("option");
option.text = files;
x.add(option);
});
When I do that, this is the result
Any idea why it's the last drop down is looking like that? This is what the php page is outputting
The easiest way, seeing as you're already using JS/jQuery would be to use $.append() doc.
Either do this as part of your return or loop through the file. You shouldn't need to create the file if you add it to the .success(data) the function of the ajax call. Simply have the PHP file you're calling echo out what you need in a format you can interpret, eg json_encode your output array.
Edit adding suggestion:
THE FOLLOWING IS UNTESTED AND PURELY FOR EXAMPLE:
NB: this expects test.php to output the formatted data as an array parsed through json_encode.
$.ajax({
url: "test.php"
}).success(function(data) {
var files = JSON.parse(data);
$.each(files, function(index, value) {
$('#result-div').append( value );
});
});
Here is a way to iterate through the data using the array map function to call jQuery's append function.
const mySelect = $('#my-select');
const files = ['path/file1.ext', 'path/file2.ext'];
files.map(x => {
mySelect.append( $('<option value="' + x + '">' + x + '</option>') );
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<select id="my-select"></select>
I want to retrieve informations from the active directory (such as thumbnail photos) using post.
<?php
/**
* Get a list of users from Active Directory.
*/
$ldap_password = $_POST['password'];
$ldap_username = $_POST['username'];
$server = 'ldap://xxxxxxxxxxxxxxxxxxxxxx';
$domain = 'xxxxxxxxxxxxxxxxx';
$port = 389;
$ldap_connection = ldap_connect($server, $port);
if (FALSE === $ldap_connection){
// Uh-oh, something is wrong...
}
// We have to set this option for the version of Active Directory we are using.
ldap_set_option($ldap_connection, LDAP_OPT_PROTOCOL_VERSION, 3) or die('Unable to set LDAP protocol version');
ldap_set_option($ldap_connection, LDAP_OPT_REFERRALS, 0); // We need this for doing an LDAP search.
if (TRUE === ldap_bind($ldap_connection, $ldap_username.$domain, $ldap_password)){
$ldap_base_dn = "OU=Employees,OU=Accounts,OU=xxxxx,DC=xxxxxx,DC=xxxxxxx,DC=com";
$search_filter = '(&(objectCategory=person)(samaccountname=*))';
$attributes = array();
$attributes[] = 'givenname';
$attributes[] = 'mail';
$attributes[] = 'samaccountname';
$attributes[] = 'sn';
$result = ldap_search($ldap_connection, $ldap_base_dn, $search_filter, $attributes);
$maxPageSize = 1000;
if (FALSE !== $result){
$entries = ldap_get_entries($ldap_connection, $result);
for ($x=0; $x<$entries['count']; $x++){
if (!empty($entries[$x]['givenname'][0]) &&
!empty($entries[$x]['mail'][0]) &&
!empty($entries[$x]['samaccountname'][0]) &&
!empty($entries[$x]['sn'][0]) &&
'Shop' !== $entries[$x]['sn'][0] &&
'Account' !== $entries[$x]['sn'][0]){
$ad_users[strtoupper(trim($entries[$x]['samaccountname'][0]))] = array('email' => strtolower(trim($entries[$x]['mail'][0])),'first_name' => trim($entries[$x]['givenname'][0]),'last_name' => trim($entries[$x]['sn'][0]));
}
}
}
ldap_unbind($ldap_connection); // Clean up after ourselves.
}
$message .= "Retrieved ". count($ad_users) ." Active Directory users\n";
?>
I tried using http://localhost:8666/web1/activedirectory.php to see if it returns anything but it returns the following error as result is >1000.
Warning: ldap_search(): Partial search results returned: Sizelimit exceeded in C:\xampp\htdocs\web1\activedirectory.php on line 28
Notice: Undefined variable: message in C:\xampp\htdocs\web1\activedirectory.php on line 46
below is the jquery where I want to link the .php file to the above file :
$('.leaderboard li').on('click', function () {
$.ajax({
url: "../popupData/activedirectory.php", // php file with link to the active directory.
type: "POST",
data: {id:$(this).find('.parent-div').data('id')},
success: function(data){
console.log(data);
data = JSON.parse(data);
$('#popup').fadeIn();
//call for the thumbnail photo
// etc ..
},
error: function(){
alert('failed, possible script does not exist');
}
});
});
FIRST QUESTION:
You have to append an img element insteadt of setting the text like this:
$('#imagesofBadges').append('<img src="' + data[0].BadgeImage + '"/>');
SECOND QUESTION:
When appending the images add a class attribute so you can fetch them with jQuery using that classname like this:
var $img = $('<img src="' + data[0].BadgeImage + '"/>'); // create the image
$img.addClass('badge-image'); // add the class .badge-image to it
$('#imagesofBadges').append($img); // append it
Now you can fetch those images using a selector like this:
$('#imagesofBadges .badge-image'); // will fetch all the elements that have the class .badge-image that are inside #imagesofBadges.
EDIT:
if you want to remove all the images inside #imagesofBadges before appending the new one use this:
// fetch all the images inside #imagesofBadges and remove them
$('#imagesofBadges img').remove();
// append the new image
$('#imagesofBadges').append('<img src="' + data[0].BadgeImage + '"/>');
First of all, the error you get has nothing to do with POST, AJAX, or PHP. It is caused by the LDAP query being too generic:
ldap_search(): Partial search results returned: Size limit exceeded
Each jQuery call can only return one image, so you need to retrieve the thumbnails one by one, and each call needs to search and return only one record (i.e. a READ, not a SEARCH).
This means that you need to send along your user ID in the PHP call so that the script may know which thumbnail to return... and this you do.
But the PHP is not using that information. You search for all the names, which means that it couldn't work anyway, but it doesn't even start because the LDAP search croaks.
$search_filter = '(&(objectCategory=person)(samaccountname=*))';
In the line above, you need to add some filter. For example, is the ID name you get in the leaderboard the SAM account name? If so, you can do something like
$kid = 'NonExistingAccount';
if (preg_match('#SAM_NAME_MATCHING_REGEX#', $_POST['id'])) {
$kid = $_POST['id'];
}
$search_filter = "(&(objectCategory=person)(samaccountname={$kid}))";
and be sure to retrieve only one record. At that point you can go about extracting the image (which if memory serves is in bitmap format), and convert it to a form suitable for jQuery:
$bitmap = $entries[0]['picture'];
// Some error checking would probably be good
$gd = imageCreateFromString($bitmap);
// Here you'll probably want to resize your image. Create
// another GD object with ImageCreateTrueColor and use imageCopyResampled
// with the appropriate size.
// Then, inform jQuery that a PNG is coming along
header('Content-Type: image/png');
// and send the PNG
imagePNG($gd);
// and nothing else (shouldn't matter, but you never know, and anyway...).
exit();
Example
You have a HTML section containing several elements (say, your employees).
VERY IMPORTANT: this section will have been generated by PHP using a LDAP search, so that you have the information required. You may need to paginate the LDAP search to avoid too many results being returned (and an error), as before.
But once you do this, you will have the distinguished name of each user.
<ul class="leaderboard">
...
<li data-dn="CN=Jeff Smith,OU=Sales,DC=Fabrikam,DC=COM">
<img class="placeholder" />
<span class="cn">Jeff Smith</span>
<span class="ou">Sales</span>
</li>
...
</ul>
In the above, you read 'Jeff Smith' and so on from the LDAP search. But you cannot easily place an image there from PHP, HTML does not permit it (okay, it does, as this answer to a similar question as yours shows, but say you prefer not to), so you put there a placeholder instead with the appropriate size using CSS.
You can also put an animated GIF that says "loading..." in the image.
To make things more efficient you save in the data-dn attribute the DN of each result.
Either on clicking or onload(), or if you have an AJAX paging on page change, you retrieve all the images. This is very similar to the code you already have.
$('.leaderboard li').on('click', function () {
// Get the image. This returns nothing if it has already been loaded.
var img = $(this).find('img.placeholder');
if (img.length === 0) { return; }
var dn = $(this).attr('data-dn');
// Load image from its DN.
// See https://stackoverflow.com/questions/4285042/asychronously-load-images-with-jquery
img.src = 'load-image.php?dn=' + dn;
});
The load-image.php script will receive $_GET['dn'] and will require to perform a LDAP read using the supplied DN, and retrieve the appropriate image attribute.
Then you just output it with header() and the image*() function you prefer (e.g. imageJPEG() or imagePNG() ).
You could do this in AJAX and send images encoded as base64 (code in the link above), but it's more complicated, and the time you save sending only one call instead of twenty for twenty images is promptly lost, with interest, when you need to send along the JPEGs encoded as base64 instead of binary, with a 5-10% increase in size if your web server gz-encodes the base64 (or a 33% increase in size when it doesn't).
Use something like
$('#imagesofBadges').append($("<img>").prop("src", data[0].BadgeImage));
I have been searching for the past hour and have not found a solution that is well suited to my situation. I have an event registration form and in order for users to have the form auto populated they can specify an id from a previous registration. There are over 20 fields.
Everything is working pretty well. I have a PHP script that creates an xml response for ajax. The xml is of form
<response>
<field1>f1</field1>
<field1>f2</field1>
etc
</response>
My javascript is
$.ajax({
type : "POST",
url : "myscript.php",
data : $(this).serialize(),
success: function(xml){
$("#field1").val($("field1",xml).text());
$("#field2").val($("field2",xml).text());
}
})
Above works fine but I don't want to manually write out each form field assignment. I want to do it in a loop. So something like this in the success function:
var fields= xmlResponse.getElementsByTagName("response");
for (i = 0; i < fields.length; i++) {
// not sure what to put here...
}
In the for loop I have to index in to the node name and value so that I can simply have a statement that would be of this form: $("#"+fields[i].nodename).val($(fields[i].nodevalue,xml).text());
I tried
$("#" + fields[0].childNodes[i]).val(fields[0].childNodes[i].nodeValue);
But that did not return the values.
Any idea on how best to do this? I feel like I am very close to having this working! Thanks!
You can use $.parseXML, and then loop over the elements with .each().
var $xml = $.parseXML(xml);
$("#response", xml).children().each(function(i, e) {
var field = e.tagName;
var value = e.innerHTML;
$("#" + field).val(value);
});
You're on the right track. What it comes down to is that when you parse an XML file, the parser doesn't care what the fields are, it'll parse it as it sees it. You would basically have to tell the script to pull certain tags with certain text. As far as I know, this is best done using the .tagName property and the tag's value and storing it in an object.
var data={}
$(this).children().each(function() {
data[this.tagName]=$(this).text();
})
You can see how this would work here:
http://jsfiddle.net/dpK7x/1/
This code does what I need but I want to store the JSON values it uses in a separate file using standard JSON format so the same data can be used elsewhere with getJSON requests.
(I need to run this to match up data returned from a getJSON request with additional values. I use the id to do the match on returned items. This is how I build the complete HTML items I need.)
CODE SAMPLE
$(function() {
var json = {
"nwsltrs":[
{
"id":"53c57dede4b07621dafde5d1",
"nwsltrNames":"Hello",
"author":"Joe"
} // these entries will grow to a hundred or more.
]
};
var titleID = "53c57dede4b07621dafde5d1"; // in actual code getting this value from a separate getJSON call
$.each(json.nwsltrs, function(i, v) {
if (v.id === titleID ){
nwsltrName = v.nwsltrNames;
author = v.author;
console.log(nwsltrName + ":" + author);
return;
}
});
});
Want the external JSON file to look like this with and use .json extension:
{
"nwsltrs":[
{
"id":"53c57dede4b07621dafde5d1",
"nwsltrNames":"Hello",
"author":"Joe",
},
{
"id":"54b57dede4b07621dafde5d2",
"nwsltrNames":"Bye",
"author":"Mary",
} // these entries will grow to a hundred or more.
]
I'm sure there are better ways to approach this and am open to hearing them—as long as I can use an external JSON file.
Solved.
Moved getJSON request that was tried earlier before posting.
It needed to run and return the data prior to this .each.
This allows me to replace the local JSON function and use a validated external JSON file here and elsewhere as desired.
We have clients that we want to collect some of their form submission data for. A user will fill out a form on their site and when the form is submitted, the following javascript is called:
/* 4. Below script will get all field name/value pairs for given form */
function cpcshowElements(f) {
var formElements = "";
for (var n=0; n < f.elements.length; n++) {
box = f.elements[n];
if (!f.elements[n].value == ""){
formElements += box.name + ":" + f.elements[n].value + ",\n";
}
}
var track = new Image();
/*send data to us*/
track.src="https://www.xxx.com/form_record.cfm?form="+formElements;
//alert("The elements in the form '" + f.name + "' are:\n\n" + formElements);
}
This calls code on our end that should grab the data sent and save it. This works great, but doesn't work all of the time. When testing, we seem to not get the data consistently. I haven't been able to figure out why this works sometimes and not others. I'm not a javascript expert so I'm not sure if it's just the way javascript works. The only thing I've been able to think might be the issue is that once the clients website finishes processing the form on their end and the user is directed to another page, the script will stop running if it hasn't already finished and so we won't get the data. Anyone have any ideas? Am I on the right track here? Any ideas on how to make it so we will get the data every time?
You could you jQuery Framework with serialize function tosubmit the form and get it input's values.
$("#bottonId").click(function(){
imageObj.src ="http://www.mypage.com/mypage?" +$("#form's ID").serialize();
});