Jump to content
Larry Ullman's Book Forums
Sign in to follow this  
Antonio Conte

Need Help With Js Code Improvements

Recommended Posts

Hey, everyone.

 

Currently working on a project that requires a lot of Javascript. This includes Ajax requests, some event listeners, Google maps integration, a Wysiwyg-editor and probable some more. I'm currently working with JQuery as I'm not much of a Javascript developer. I will group the code by usage, show an example and tell you if I experience weird behavior.

 

1. Drop-down search functionality (SOLVED)

 

2. Multiple file uploads as attachments

Intro: The system is based around offers. These offers should allow attachments and possibly a main image. (Think like Wordpress' main article image)

 

Problems/questions/etc:

1) I want the uploading to be done with Ajax. I found a good script that handles this. The problem is that the attachments must be tied to the ID of an offer. This ID, however, does not exists before an offer is published or saved as a draft. How can I tie these two together?

2) As users must be logged in, I create a folder for the user if one does not already exists. This folder is named by the User-ID. This is done because I remember reading about a problem occuring when too many files are lookated in the same folder. Is this neccasary or good, or would you recommend something else?

 

Table structures and data flow: (Only the key structure)

Offers ( offer_id, status, user_id* ..... )

Offers_attachments ( offer_id, path, extention.... )

Users ( user_id, ...info... )

 

Upload script used: (Not that it really matters)

valums file-uploader

 

Help me pick a solution:

1.) A two-step process. The users fill out vital information first, click next, (and the article is saved) then add attachments and save with a status.

2.) An empty offer is inserted to the DB when a user clicks "Add new offer". We now have an offer ID to tie attachments to. A daily cron job deletes offers/attachments that were never "Saved" by clicking "Save the offer" by the user.

3.) Attachments are tied to the user instead. The users can then add uploaded attachments found in the database related to their user.

Edited by Antonio Conte
  • Upvote 1

Share this post


Link to post
Share on other sites

I agree with you that if the data will rarely change, just dumping it all in a JSON or CSV file, etc. will be your best bet. It'll definitely speed things up.

 

To answer your original question though, as you know, I'm pretty comfortable with JS, but with that said, I rarely use jQuery, and I have never used the ajax method, but I am wondering why you're using the post method instead of the ajax method. What's the reason? Is the post method getting you want you want? I'm thinking that a get request with the ajax method in jQuery might better suit your needs.

 

I'm sure you already know this, but I'd probably do the following to at least locate the problem:

1) Make sure your Ajax server-side script is receiving the correct value (i.e., 0-3).

2) Either alert or dump to the console log the HTML returned by your Ajax script to confirm you're getting what you want.

 

Also, as a general rule, it's quicker to return as little data as possible from your server-side script via Ajax. As such, I'd return only the essential values for the model select element (probably in CSV format), and then reconstruct all the HTML on the JS side. It'll give you a speed boost (although in this case, maybe not a huge one).

 

Of course, if you decide to just dump everything in a file, then I guess all the stuff I stated above is of no value.

Well, please let us know what you want to do.

  • Upvote 2

Share this post


Link to post
Share on other sites

Good. The only problem with that method is that I don't really know how to work with JSON data in Javascript. The HTML method worked fine, so I stuck to that initially. I'm guessing that getting the data as JSON would be pretty simple, as I'm only generating HTML in the form of <option="<?=$id;?>"><?=$value;?></option>. This data is then echoed and then appended to the #models select box. Generating the HTML client side is something I would like to do.

 

The reason for using the .get-method is that I found the .ajax() or .post() methods harder to understand. I got the .get()-method to work quickly, so I stuck to that. I wouldn't mind a switch, or even use regular Javascript if that doesn't complicate things a lot.

 

Regarding "the problem", the Ajax script always receives correct values. If not, a standard value is used, so the problem must be related to the events not being sent (as a result, no a.get()-request is done). .change() won't fire an event if there is no change in values. I'm looking for something to bullet-proof the event handling. The problem is hard to replicate effectively, but sometimes, the select box just refuses to populate. A refresh solves that problem.

 

As an example, let's say Alfa Romeo is used, a search is done, then the user's used backspace to go back. Then, a new click on Alfa Romeo won't load the models as the value has not changed.

 

Links can be sent on PM for those able to help. As the project is still in development, I don't want to post links in a public forum.

Share this post


Link to post
Share on other sites

Working with JSON data is the same as working with any Javascript object. If you know how to declare and use a Javascript object, you're good to go. As a simple example of an object that might suit your needs:

 

 

var brands_models = {

 alfo_romeo: ['Model 1', 'Model 2', 'Model 3'],

 aston_martin: ['Model 1', 'Model 2', 'Model 3', 'Model 4'],

 audi: ['Model 1', 'Model 2']

};

 

(Please excuse my generic model names, as I'm not an expert on cars, but) the above illustrates a simple JS object declaration. In fact, since you're already pulling numeric values from the brands select, you could even ditch dealing with an object altogether, and go straight to a simple multidimensional array. Both would work fine. Once a brand value is selected, then you'd use the onchange event on the select element to get the value.

 

While you seem to have already done the same thing in jQuery, here's the basic vanilla JS equivalent of getting the value of the select option every time a new option is selected:

 

 

<form>

 <select>

   <option value="1">Ferrari</option>

   <option value="2">Lamborghini</option>

   <option value="3">Porsche</option>

 </select>

</form>

<script>

 document.forms[0].elements[0].onchange = function () {

   alert(this.value);

 };

</script>

 

Note that the onchange event does NOT fire when the same element is selected twice in a row. For example, the select element starts with the Ferrari option. If you select Ferrari while Ferrari is already selected, the event will not fire. This actually makes sense though, and shouldn't be a problem.

That help at all?

  • Upvote 2

Share this post


Link to post
Share on other sites

To address your other points Antonio (sorry, I forgot to in the last post), you're right in that the onchange event is not fired when the same option is selected twice in a row. The only ways around this is to set up a "Search" button, which grabs the value of the selected option every time (regardless of how many times the same option was selected in a row), or to reset the brands select element every time an option is selected. For example, you could make value 0 the following:

 

<option value="0">--</option>

 

And reset to that every time.

However, at the end of the day, none of that should be required. I'd simply store the selected option value in a global JS variable, and whenever the "Refresh" button is clicked, the list is refreshed on whatever value is in that variable, regardless of whether it's the same as before or not.

 

Point being, you can slice this problem a million ways, and JS can be coded to accommodate any interface design you want, but I suppose you first need to decide how you want the interface to function.

  • Upvote 2

Share this post


Link to post
Share on other sites

I got to thinking more about your issue, and I really can't help but think a user would never have to click the same select option more than once in a row. By your own admission, the data will change so infrequently that you're willing to put it in a simple text file.

 

Anyway, to be honest, I'm still not sure exactly what you want, so I'll leave it up to you to decide.

 

There are a couple of relevant SO posts I found on this issue:

http://stackoverflow.com/questions/4092144/select-the-same-option-multiple-times-onchange-without-changing

http://stackoverflow.com/questions/5964362/select-already-selected-item-in-dropdown-select-list

  • Upvote 1

Share this post


Link to post
Share on other sites

Thanks, Jon

 

I think I'll go for creating a multidimensional array. I think I'll write to a .js-file every time a change is done to the car database. Because we'll only deal with new cars this should cut the amount of queries needed to search by a good portion. It's not really a problem, but the site will feel a lot quicker for sure. I'm mostly thinking about this to reduce the amount of data for mobiles.

 

Regarding the events, I've found out that I can do something along these lines:

 

	 // Will perform an Ajax-search for models
	 var getBrandModels = function(brand_id) {
		 $.post(
				 'ajax/get_models_by_brand_id/'+brand_id,
				 function(data) { $("#model").html(data); }
		 );
	 }
	 // Perform model search when change-events are caught
	 $("#brand").change( function(){getBrandModels($(this).val())} );
	 // Duplicate for other events.

 

Haven't really looked that much at other events yet, but I've seen .click(). It seems to be handling to special cases I've had problems with, but will perform a new post request for every click event. With a static JS array instead of requests, though, this seems like a viable solution.

 

Will update the first post with new questions. I'm considering this one improved and solved.

 

A quick one, though. How should i save datasets in JS? Should I link to a javascript file, include the array in script-tags or what would you recommend?

Share this post


Link to post
Share on other sites

Antonio, if I am understanding what you want to accomplish (and I think I do), then you don't need to query a separate script every time someone selects an option from the select element. The whole benefit of keeping the data on the client side is that data access is instantaneous.

You can put the actual data array in either a separate JS file, which you'd load separately (my recommendation), or you can put it directly in your main JS file. The speed at which it loads will be the same.

 

Anyway, here's a quick demo of how I'd handle it (and I did actually take the time to find some real car models this time; I'm learning!). Note that for the demo, I'm putting the multidimensional array in the same script, but you can put it in a separate script, which would be loaded via a separate set of script tags.

 

<!DOCTYPE html>

<html lang="en">

 <head>

   <meta charset="UTF-8">

   <title>JS select element generator</title>

 </head>

 <body>

   <form>

     <select id="brands">

       <option value="0">--</option>

       <option value="1">Ferrari</option>

       <option value="2">Lamborghini</option>

       <option value="3">Porsche</option>

     </select>

     <div id="models_container"></div>

   </form>

   <script>

     var models = [];

     models[1] = ['--', '360 Spider', 'Enzo Ferrari', 'F430 Spider', '430 Scuderia', '599 GTB Fiorano', 'Scuderia Spider 16M'];

     models[2] = ['--', 'LM002', 'Diablo', 'Murciélago', 'Gallardo', 'Reventón', 'Aventador', 'Sesto Elemento'];

     models[3] = ['--', 'Boxster', 'Cayman', '911', 'Panmera', 'Cayenne'];

     document.getElementById('brands').onchange = function () {

       if (this.value > 0) {

         var value = this.value;

         var html = '<select id="models">';

         for (var i = 0, len = models[value].length; i < len; i++) {

           html += '<option value="' + i + '">' + models[value][i] + '</option>';

         }

         html += '</select>';

         document.getElementById('models_container').innerHTML = html;

       } else {

         document.getElementById('models_container').innerHTML = '';

       }

     };

   </script>

 </body>

</html>

 

As always, I'm not suggesting that my code is the most solid, but for demo purposes, I think it's okay.

Is this the kind of thing you're looking to accomplish?

  • Upvote 1

Share this post


Link to post
Share on other sites

Yes, perfect. I think I'll go for the separate file option. The only thing I need additionally, is keys for the models, as they are connected to rows in the models table. I also want more info here, like number of models per brand, etc. I should be able to fix that my selves now that I know how.

 

I have learned a lot about JS lately. Got most of my solutions to work so far. Still need a little help making whole table rows clickable, improve the speed on google maps, changing my file upload script a little, etc. I'll edit my first post soon to explain the problems.

 

Thanks, Jon.

Share this post


Link to post
Share on other sites

No problem.

As a note, if you want labels for your indexes, I'd go with an object instead of an array. The syntax is only slightly different.

 

One interesting (or perhaps weird) thing about JS is that the line between arrays and objects is super blurred. In fact, arrays are a subset of the Object object, and the only difference between the two (besides slight syntax, of course), is that objects have named indexes, and arrays have numbered indexes.

 

As another note, when you update your other post, please be sure to add a new post to the current thread and not just edit an existing post, or I probably won't notice, as I use the "View New Content" feature on this forum to catch new stuff.

 

Thanks.

  • Upvote 1

Share this post


Link to post
Share on other sites

Worked perfectly when i created JSON objects from the PHP array. I had to remove the property "make_name" from the object, but I guess never used it anyway. Here is what I ended up with:

 

<!DOCTYPE html>

<html lang="en">

<head>
   <meta charset="UTF-8">
   <title>JS select element generator</title>
</head>

<body>

<form action="" method="get">
   <select name="brands" id="brands">
    <option value="0">Velg bilmerke</option>
    <option value="1">Alfa-Romeo</option>
    <option value="2">Aston Martin</option>
    <option value="3">Audi</option>
   </select>

   <select name="models" id="models">
    <option value="0">Pick a car brand</option>
   </select>

   <button type="submit">Search</button>
</form>

<script src="models.js"></script>

<script>
   document.getElementById('brands').onchange = function ()
   {
    var html = '<option value="0">All models</option>';

    for (var key in models[this.value])
    {
	    if (models.hasOwnProperty(this.value))
	    {
		    html += '<option value="' + key + '">' + models[this.value][key] + '</option>';
	    }
    }

    document.getElementById('models').innerHTML = html;
   };

</script>
</body>
</html>

 

The JS file holding JSON (models.js):

var models = {"1":{"1":"Alfa-Romeo Giulietta","2":"Alfa-Romeo MiTo"},"2":{"3":"Aston Martin DB9","4":"Aston Martin V8 Vantage"},"3":{"5":"Audi A1","6":"Audi A3","7":"Audi A4","8":"Audi A5","9":"Audi A6","10":"Audi A7","11":"Audi A8","12":"Audi Q3","13":"Audi Q5","14":"Audi Q7","15":"Audi R8","16":"Audi RS4","17":"Audi RS5","18":"Audi S3","19":"Audi S4","20":"Audi S5","21":"Audi S6","22":"Audi S8","23":"Audi TT","225":"Audi Z-Serie"}}

Share this post


Link to post
Share on other sites

Looks fine, but two questions:

1) If you're using all number keys, why not just use an array (as opposed to making the numbers into strings for an object)? The numbers don't have to be sequential for the sake of an array in JS.

2) Is the following a spelling mistake? (Sorry for being so picky.)

"Audi Z-Serie"

Share this post


Link to post
Share on other sites

I'm thinking more about the generation of the code. This is what I got by using json_encode(). I also think this structure is easier to change as I can add new keys very easily. (In the PHP array, and it will just be converted for me)

 

Yes. Should be X-series. Must have mixed up with BMW. Cars is not my speciality eighter.

Share this post


Link to post
Share on other sites

Ah, yes, well naturally, if you use the json_encode function, you will get a JS object, even if all your keys are numbers. You'll just get string numbers.

 

Anyway, whatever works for you, right? It's not a big deal. Just kinda noticed.

Best of luck with your project!

 

Edit: As a (hopefully final) side note, if you're planning on having your site work on mobile as well, the onchange event does not work properly in iOS (but I think it works okay in Android OSs). The workaround is to add the onblur event to the elements with the same behavior as the onchange event. You should be fine then.

Share this post


Link to post
Share on other sites

This is an interesting piece of code, have to make one of these later on but with no extension limit. I am almost at the end of the js book now, this topic was briefly mentioned in it.

Share this post


Link to post
Share on other sites

Interesting question, Antonio. For the time being, I'll keep things rather abstract (as you seem like the kind of guy that likes to solve things on his own), but if you want specific code snippets, I can provide that too.

 

As a general point, I always try to put the user interface, user experience and the user's point of view first. With that said, I don't know exactly what you mean by "offer", but if offers are often tied together with attachments (files to be uploaded?), then as a user, I would prefer to have one screen from which I can do everything at once (i.e., write an offer and add as many attachments as need be).

 

Also, from a development/site performance point of view, I don't like the idea of a bunch of half-finished offers floating around and a cron job having to run every day to clean all that up.

 

So that leaves us with two viable options: Tie offers and attachments to the user's ID (my preference), or tie attachments to just offers (and I guess then tie offers to user IDs, although I'm not sure about your intentions if you go this route).

 

The reason I prefer the first route is because you stated that a user must already be signed in to fill out an offer and add attachments. As such, you already have ready access to a unique ID. This will simplify the logic and decrease the number of required DB queries.

 

To be a bit more specific, if you link everything to a user ID, I'd do the following:

1) When the user signs in, assign their user ID to a session variable.

2) Create one page from which (signed-in) users can both fill out an offer and add all the necessary attachments for that offer.

3) When the user clicks the "Add Offer" (or whatever) button, use Ajax to make two post requests to server-side scripts. One request would send the standard (text) post data (i.e., the offer text), and the other would send the attachments. I recommend having two separate scripts to handle the two types of uploads.

With both requests, you should also send the user ID, so that you know what to link to. You may want to consider doing what Gmail does, which is allow multiple attachments, but only one at a time and immediately begin the file upload as soon as they select a file and hit OK.

4) In your two scripts called from Ajax, you then go through the standard routine of scrubbing the input and making the proper DB insertions based on the provided user ID.

5) Report something back to the client side to show either success or failure for each call to an Ajax script.

6) Done.

 

If you decide to instead link to an offer, then you will of course have to have the user upload the offer before the attachments, which I don't like for two reasons:

1) You have to make the offer/attachment thing a two-step process, which seems unnecessary, or...

2) You have to wait until the offer is uploaded to upload all the attachments at once, which could be slow.

 

So, that's my idea.

Please lemme know what you think.

Share this post


Link to post
Share on other sites

Ok, Jon. I went with that approach. I've not really gotten it to work that great yet, but it does work according to functionality. I need a little help with formating/restrictions and user feedback, though.

 

This is what I've done:

- Added files uploaded by the user to a select element as options.

- The option values holds the file_ids from the DB rows.

- I use span to "add" attachments. This add button has a JS event handler listening to .click.

- When .click fires, I take the option value and add it to a hidden input field.

- Next add concatenates a new ID to the hidden input with comma-separation.

- I toggle a success message telling the file was added.

 

What I need to improve:

- The same ID can be added multiple times.

- How can I delete values from this String using the "[X]" elements? I'm blank here...

- How do I get the file names? I want to show the file names inside the add/remove (bootstrap-) alert boxes.

 

Some thoughts:

- I think a JS array would be easier to add/remove IDs from. I just don't know how do that in a POST-friendly manner. If that's possible, then sure, let's go.

- Maybe I should remove the select options already added by the user? That's a possible solution

 

The option value is set to file_ids. I'm then using a span button to add these ID's to a comma-separated string. The string is then added to a hidden input field that will hold all files attached to the offer. This way, I can add these IDs to the offers_attachment table.

 

I have tried to explain how this should work graphically in the file below. It's JQuery and bootstrap CDN'd, so it should work out of the box.

 

Here's the file

<!DOCTYPE html>
<html lang="en">
 <head>
   <meta charset="utf-8">
   <title>File Attachments  Bootstrap</title>
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <meta name="description" content="">
   <meta name="author" content="">

   <!-- Le styles -->
   <style type="text/css">
       body {padding-top: 20px;padding-bottom: 40px;}
       /* Custom container */
       .container-narrow {margin: 0 auto;max-width: 700px;}
       .container-narrow>hr {margin: 30px 0;}
       /* Supporting marketing content */
       .marketing {margin: 60px 0;}
       .marketing p+h4 {margin-top: 28px;}
       .hide { display: none; }
   </style>
   <link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.2.1/css/bootstrap-combined.min.css" rel="stylesheet">
   <script src="http://code.jquery.com/jquery.min.js"></script>
</head>

 <body>

   <div class="container-narrow">

  <div class="masthead">
    <ul class="nav nav-pills pull-right">
	  <li class="active"><a href="#">Home</a></li>
	  <li><a href="#">About</a></li>
	  <li><a href="#">Contact</a></li>
    </ul>
    <h3 class="muted">Attachment test</h3>
  </div>

  <hr>

  <div class="row-fluid form-horizontal">
    <form action="" method="post" class="form form-horizontal">
        <h3 class="controls">Attach files <small><a href="#">Upload new files</a></small></h3>
           <div class="controls">

               <div class="input-append">
                   <!-- Users uploaded files from the DB -->
                   <select name="files" id="files" class="input-xlarge">
                       <option value="16">Brazil.png</option>
                       <option value="17">China.png</option>
                       <option value="18">tsl_1.jpg</option>
                       <option value="19">tsl2.jpg</option>
                   </select>

                   <!-- Add files to attachment via this -->
                   <span class="add-on btn btn-success" id="add-file"> + </span>
               </div>
               <!-- Hidden input holding file IDs -->
               <input type="hidden" name="attachments" id="attachments" value="">
               <p id="attachment-str"><p>
           </div>

           <br>

           <div class="controls alert alert-success" id="add-message">
               <button type="button" class="close" data-dismiss="alert">×</button>
               <p>The file <strong>{filename}.{ext}</strong> added successfully!</p>
           </div>

           <hr>

           <!-- List of attached files with remove option -->
           <div class="controls">
               <h4>Files attached:</h4>
               <ul id="filelist">
                   <li>Filename.png <a href="#"><i class="icon-remove"></i></a></li>
                   <li>Filename.png <a href="#"><i class="icon-remove"></i></a></li>
                   <li>Filename.png <a href="#"><i class="icon-remove"></i></a></li>
               </ul>
           </div>

           <div class="controls alert alert-error" id="delete-message">
               <button type="button" class="close" data-dismiss="alert">×</button>
               <p>The file <strong>{filename}.{ext}</strong> was successfully removed!</p>
           </div>

           <div class="control-group">
               <div class="controls">
                   <h3>Save offer</h3>

                   <button class="btn btn-success" name="save" value="save" type="submit">
                       <i class="icon-ok-sign icon-white"></i> Save and Publish
                   </button>
                   <button class="btn" name="save" value="draft" type="submit">Save draft</button>
               </div>
           </div>

           <hr>
           <?php  if ( ! empty($_POST) ) { unset($_POST['files']); unset($_POST['save']); // Remove keys not needed
               // Debug array
               echo '<h5>POST DATA</h5><pre>' , print_r($_POST) , '</pre>';
           } ?>

       </form>


  </div>

  <hr>

  <div class="footer">
    <p>© Company 2012</p>
  </div>

   </div> <!-- /container -->

   <script>

   $(document).ready(function() {

       $("#add-message").hide();

       // On click, add select value to hidden input
  	 $('#add-file').click(function() {
              var file = $("#files").val();            // Get select value
              var files = $("#attachments").val();        // Get current input value
              var str = ( files.length > 0 ) ? files+", "+file : file;    // Add int to String

              // Assign string to input
           $("#attachments").val(str);

              // Toggle file added message
              $("#add-message").show(500).delay(800).queue(function(next){
               $(this).hide(500);
               next();
           });

  	 });
   });
   </script>

   <!-- Le javascript
   ================================================== -->
   <!-- Placed at the end of the document so the pages load faster -->
   <script src="//netdna.bootstrapcdn.com/twitter-bootstrap/2.2.1/js/bootstrap.min.js"></script>

 </body>
</html>

 

Thanks in advance to anyone helping.

Share this post


Link to post
Share on other sites

Something I should have mentioned in my last post is that file uploading with JS is a tricky beast; tricky in that IE only supports it in IE10. Great!

As usual though, there are hacks and ways to get around this problem (and I assure you they're no fun). The long and short of it is this:

- If the browser supports the HTML5 File API and XMLHttpRequest Level 2 (e.g., Chrome, Firefox, IE10, Safari, Opera, etc.), you should use that.

- If the browser does not support the File API and XMLHttpRequest Level 2 and you still want to support JS file uploads, you'll have to use a hidden iframe.

 

To describe the hidden iframe method real quick, you need to place an iframe somewhere in your HTML. Naturally, you'll want to hide it with display: none. Next, upon selecting a file to upload from a form, you have to use JS to submit the form to the script in the hidden iframe. From that script in the hidden iframe, you then need to do your standard file scrubbing operations and save the file to the server. Once that's done, you then need to echo the necessary response back to JS, which can then do whatever is necessary to notify the user that the file was successfully uploaded.

 

So, yeah, it's basically a big ol' cluster f***. (Sorry for being so raw tonight.) You can do that if you want, but my recommendation is to use the File API if it's supported, and if not, just force the user to reload the page to upload the file. I don't really think users still using IE8 and the like will complain.

 

Now, if the browser supports the File API and XMLHttpRequest Level 2, then you're in luck. The following page explains how to get the file name, etc. very easily using the File API:

http://www.html5rocks.com/en/tutorials/file/dndfiles/

 

And as a basic demo, try the following code with any file on your PC to quickly see the File API in action:

 

<!DOCTYPE html>

<html lang="en">

 <head>

   <meta charset="UTF-8">

   <title>File upload test</title>

 </head>

 <body>

   <form action="" enctype="multipart/form-data" method="post">

     <input type="file" id="the_file" name="the_file">

   </form>

   <script>

     document.getElementById('the_file').onchange = function (e) {

       var file = e.target.files[0];

       for (var prop in file) {

         console.log(prop + ': ' + file[prop]);

       }

     };

   </script>

 </body>

</html>

 

The above will give you quick access to the file name, etc. If you actually want to upload the file using JS/Ajax without a hidden iframe, you can use a FormData object, which is supported with XMLHttpRequest Level 2. As far as I know, all browsers that support the File API support XMLHttpRequest Level 2 as well, so that shouldn't be an issue. The following briefly explains how to use a FormData object to accomplish this:

http://timothypoon.com/blog/2011/05/10/ajax-uploading-with-html5s-file-api/

 

Basically, you have to do a standard Ajax POST to a PHP script, but in order to properly format the file data and send it to the PHP script via a POST request, you need to use the FormData object.

 

Hopefully, all of the above answers any questions you may have about handling files with JS. To answer your first question about the same ID being used multiple times, I'd do the following:

Every time a user uploads a file, I'd store the file name in a JS array, and if they try to upload a file with the same name, I wouldn't allow it. Of course, they *could* get around this, but they'd really have to be trying hard to do so (and for what reason?!).

 

Related to the previous point, I'm not sure I quite get why you first add all uploaded files to a select drop-down and then allow the user to choose which of those files to attach to the message. Isn't the assumption that if a user chooses to upload a file, then they want to use it as an attachment?

 

Not to sound overly critical of your method, but if I were doing the same thing (i.e., what I was thinking when you first proposed what you wanted to do), I would do the following:

- Below the text input/text area, I'd add either a file upload form element or a link for uploading files.

- When a file is selected, JS adds the file name to an array, which is used to ensure that the same file isn't uploaded more than once, and the file is then uploaded to the server using an Ajax POST request and the FormData object.

- Upon a successful upload, a message is echoed back to the user, and the file name is displayed on the screen, letting the user know that the file has been successfully uploaded and "attached" to the message.

- Rinse and repeat as necessary.

- You could also add a delete button for deleting attachments.

 

By doing the above, you don't need to worry about IDs or anything like that. The uploaded files are in an array, and that array can be used at any time to check for the repeated uploading of the same file.

 

Lastly, I'm not sure what you meant by the following question. Could you please clarify? Thanks.

- How can I delete values from this String using the "[X]" elements? I'm blank here...

 

Sorry for the long, and possibly unhelpful, post.

Share this post


Link to post
Share on other sites

Uploading images is not really the problem. I have solved that already. I went with a standard single file upload operation here. The audience is car retail dealers, and trust me, you'll find a lof of IE6, 7 or 8 there. In other words, not really any need for anything fancy. If I should rephrase that, I would say it's not really a priority at this point. I will definitely look at improving that later on though, so thank you very much for providing tips in that regard.

 

What I try to do here is to attach/detach already uploaded images, identified by a primary key in the file table, to a car offer. This is what I tried to demonstrate by the $_POST key "attachments". As you can see, the "+"-button will add an image ID to a hidden input. This comma-separated String should then be used to add attachments to a table of this form:

 

offer_attachments( attachment_id, user_id, file_id, offer_id )

 

I will set file_id and offer_id to unique, so the DB will prevent duplicates in practice. The current solution, as shown in my script, is not that good though. I'm stuggling with building attachment lists, add operations for detaching files, and for messages when an image is removed.

 

Long story short. I think a JS array approach, where the array is converted to a comma-seperated String at submit, would be the best approach. This will allow me to push values to the array (and hopefully prevent duplication) on adding, popping the value from the attachment array on detachment (delete) and so forth.

 

With these new information, I'm betting you can identify a simple way to do this. My problem is lack of experience with JS. I can't really identify a good approach for doing this.

 

Edit: Updated post.

Share this post


Link to post
Share on other sites

Okay, I think I better understand now. Sorry for the rather off-topic post before.

 

From your latest post, here's my take on what you want to do using JS:

- You want to be able to populate the list (i.e., select element drop-down list) of attachments.

- You want to be able to detach files.

- You want to display a message when one or more images are detached.

 

As far as I can tell though, if you're going with simple code that's compatible with IE6-8, then you shouldn't use JS for any of this.

Through your own admission, you're already using a standard (non-JS) single-file uploading interface, right? If that's the case, then every time you upload a new file, the attachments list would automatically be updated via PHP (and a call to the DB), right? I mean, if you can only upload a single file at a time by reloading the page and calling a PHP script anyway, then it seems like the attachments list would never be populated via JS. Am I wrong?

 

Likewise, I'm assuming that you're calling a PHP script and reloading the page whenever a detach operation is performed, right? If that's the case, then I'm thinking that you can use PHP to display the appropriate message as well, no? Again, if my understanding is wrong, please let me know.

 

Lastly, you could hypothetically use JS to create a queue of files to detach in batch, and then send that string to a PHP script via Ajax, but if nothing else requires JS/Ajax, then why use JS for this one thing? I'm not saying you can't or shouldn't do it, I'm really just trying to understand what you want, as I'm still admittedly a bit confused. Simply detaching one file at a time (i.e., per page reload) just like how files are attached seems fine to me, given your audience.

 

Lastly, if you want to use JS for any of this (with the exception of perhaps building a string of files to detach in batch, as you suggested), then you are going to want to use the File API, etc. I recommended in my last post, which are only available in certain HTML5-ready browsers.

 

Really though, I should apologize, as I feel like I'm misunderstanding something you're trying to say and only causing you more trouble and grief in the end.

Please let me know where I'm misunderstanding you, and hopefully I can help, as I would like to help, if possible.

  • Upvote 1

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
Sign in to follow this  

×
×
  • Create New...