0

I currently have a functionality where the user can upload and display multiple images at once as a preview on top of a modal. Ideally, I would like to allow the user to click on one of the displayed images and add it to an array on a click event so that they can then hit a button to submit the images for processing somewhere. I've tried for a few hours trying to code this out but have hit a brick wall and wouldn't mind some guidance on the matter! I'd love to be able to implement only HTML, CSS and vanilla JS... any suggestions or offerings of help would be appreciated! I searched online a fair bit but couldn't really grasp many of the concepts offered...

<!--Modal code: -->
<div id="simpleModal" class="modal">
  <div class="modal-content">
    <div class="modal-header">
      <span class="closeBtn">&times;</span>
      <h2>Image search and processing: </h2>
    </div>
    <div class="modal-body"> 
      <form id="modal-form" class="form">
        <label for="files">Select multiple files: </label>
        <input id="files" target="_blank" type="file" onchange="previewFiles()" multiple/>
        <output id="result">
        <button type="submit" class="floating-btn" value ="submit">+</button>
        <button type="reset" class="floating-btn2" value ="reset" onclick="return hideImage()">x</button>
        
      </form>
    </div>
    <div id="preview"></div>
</div>
</div>

<script>

  //code to render image files to modal
  function previewFiles() {

  var preview = document.querySelector('#preview');
  var files   = document.querySelector('input[type=file]').files;

  function readAndPreview(file) {

  // Make sure `file.name` matches our extensions criteria
    if ( /\.(jpe?g|png|gif)$/i.test(file.name) ) {
      var reader = new FileReader();

      reader.addEventListener("load", function () {
        var image = new Image();

        //styling in JS //
        image.height = 160;
        image.width = 160;
        image.style.flexDirection = "row"; 

        image.title = file.name;
        image.src = this.result;
        
        preview.appendChild( image );

        }, false);
        

      reader.readAsDataURL(file);
    }

  }

  if (files) {
    [].forEach.call(files, readAndPreview);
  }

}
    //delete form 
function hideImage() {
    document.getElementById("modal-form").reset(); //reset form
    var preview = document.querySelector("#preview");
    preview.innerHTML = '' //set preview to null
    </script>

}


/* floating buttons: */
.floating-btn{
    width: 80px;
    height: 80px;
    background: #0B406D;
    display: flex;
    border-radius: 50%;
    color: white;
    font-size: 40px;
    align-items: center;
    justify-content: center;
    text-decoration: none;
    box-shadow: 2px 2px 5px rgba(0,0,0,0.25);
    position: fixed;
    right: 120px;
    bottom: 20px;
    outline: blue;
    border: none;
    cursor: pointer;
}
.floating-btn:hover {
    background: #4D89C8;
}

.floating-btn2{
    width: 80px;
    height: 80px;
    background: #0B406D;
    display: flex;
    border-radius: 50%;
    color: white;
    font-size: 40px;
    align-items: center;
    justify-content: center;
    text-decoration: none;
    box-shadow: 2px 2px 5px rgba(0,0,0,0.25);
    position: fixed;
    right: 20px;
    bottom: 20px;
    outline: blue;
    border: none;
    cursor: pointer;

}
.floating-btn2:hover {
    background: #4D89C8;
}

/*Modal styling: */

.modal{
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, 0.7);
    position: fixed;
    top: 0;
    z-index: 1;
    display: none;
    justify-content: center;
    align-items: center;
}
.modal-content{
    width: 80%;
    height: 80%;
    background-color: rgba(255, 255, 255, 0.9);
    border-radius: 4px;
    padding: 15px;
    margin: 20% auto;
    box-shadow: 0 5px 8px 0 rgba(0, 0, 0, 0.2), 0 7px 20px rgba(0, 0, 0, 0.17);
    animation-name: modalopen;
    animation-duration: 1s;
    flex-direction: column;
    justify-content: space-around;
}
.modal-header{
    font-size:12pt;
    color: black;
}
.modal-header h2{
    margin: 0;
}
    
.modal-body{
    width: 33.33%;
    padding: 5px;
}
.closeBtn{
    color: #ccc;
    float: right;
    font-size: 50px;
}
.closeBtn:hover,.closeBtn:focus{
    color: red;
    text-decoration: none;
    cursor: pointer;
}
@keyframes modalopen{
    from{opacity: 0}
    to {opacity: 1}
}


/*Image displaying style: */
form{
    margin-top:10px;
    padding: 5px;
    border-radius: 4px;
    margin: 0 auto;

}
a img{
    float: left;
    width: 150px;
    height: 150px;
    padding-right: 15px;
    box-sizing: border-box;
}
img:hover {
    transform: scale(1.5); 
    cursor: pointer;
}
iamqaboos
  • 39
  • 7
  • What is the issue? – iota Aug 19 '20 at 14:59
  • I don't understand how to implement the code required and after a long time hitting a brick wall, I thought I'd ask for advice. I want the user to be able to click on one of the previewed images and then add that image to an array for submission on the form (which goes somewhere for processing). I can display the images that the user uploads, but they may not want every image they picked from a bulk.. so i thought clicking on one to add to an array will help solve the issue, so that all selected in the array can be submitted. – iamqaboos Aug 19 '20 at 15:02

1 Answers1

1

While there can be complicated ways like using FormData and ajax to submit the form it's better to always go with simpler ones. One of such is below

Add a hidden field in your form

      <input type="hidden" name="list" id="list">
  </form>

Create a variable that will hold an array var sList = []

Now just take this function it appends to that array and serializes that data into the hidden field

function addToArr(item){
  var index = sList.indexOf(item);
  if (index == -1) { //if not already added
    sList.push(item) // add
  }
  document.getElementById('list').value = JSON.stringify(sList);
}

That's it now in your reader load event listener add this one line

reader.addEventListener("load", function () {
  var image = new Image();
  //other code       
  //..

  image.src = this.result;
  image.onclick = function(){ addToArr(file.name); } // <-- this line

  preview.appendChild( image );

  }, false);

Now whenever user clicks any image, its name will get into the list array and therefore in hidden field (You may verify using inspect element in devtools). So when you submit the form, on you server side just decode/parse the json and you know which images user wants (the names) by that you can filter on the actual file objects. You haven't told what language you are using at the server so for now this should suffice

Viney
  • 6,629
  • 3
  • 21
  • 40
  • To answer your question about the language that server is using, we have only been told to implement HTML, CSS and JS - we are using Tornado API which requests from an AWS S3 database, which then brings the image back to us which we must display on the screen... and then allow the user to select the images they want to be processed in the form... Does this info help? Not sure if that will affect what you've written... – iamqaboos Aug 20 '20 at 02:12
  • I see.. Does the tornado API returns a json containing the urls of images? something like [this](https://www.airport-data.com/api/ac_thumb.json?m=C822AF) which you then JSON.parse() into a javascript structure, loop over and do `var image = new Image();` ... – Viney Aug 20 '20 at 03:56
  • I believe it does return JSON! – iamqaboos Aug 20 '20 at 05:57