paulmo Posted April 11, 2017 Share Posted April 11, 2017 (edited) W3S, goal is to "upload" local image to display on page via JS. I've grabbed this JQuery script somewhere, can browse and select file, now how to integrate with onclick function (that's working with other text inputs)? Right now nothing's happening, no errors and no images in Network Monitor. <form action="#" onsubmit="return false"> Upload image <input type="file" id="upld" value="Choose file"/> <img id="compImg" src="#" onClick="this.select();"/> ..........etc........ // in button onclick function...v v var upldI = document.getElementById("upld").value; var compImgVar = document.getElementById("compImg").value; var img = document.createElement("img"); src = compImgVar; img.src = src; //File Upload $(function () { $(":file").change(function() { if(this.files && this.files[0]) { var reader = new FileReader(); reader.onload = imageIsLoaded; reader.readAsDataURL(this.files[0]); } }); }); function imageIsLoaded(e) { $('upldI').attr('src', e.target.result); }; container.appendChild(img); document.body.appendChild(container); }; Edited April 11, 2017 by paulmo formatting Link to comment Share on other sites More sharing options...
dsonesuk Posted April 11, 2017 Share Posted April 11, 2017 Anything referring to 'upldI' variable as stated here var upldI = document.getElementById("upld").value; Will only refer to the value of input element with id 'upld'. This is referring to text string not variable of element selector for class or id $('upldI').attr('src', e.target.result); problems (1) because 'upldI' variable has a var preceding it, its scope is restricted to scope of onclick event function, it need to be declared outside functions to make it globally available. (2) As stated at beginning if this variable is global now, it will refer to elements value not element with id 'upldI'. (3) It targets in wrong element anyway it should target element with id "compImg", this is the img that has 'src' attribute, OR by using corrected variable reference it would target file input then using next() move to next sibling element which is the img $('#'+upldl.id).next().attr('src', e.target.result); OR just use actual img id selector ref $('#compImg').attr('src', e.target.result); Link to comment Share on other sites More sharing options...
paulmo Posted April 11, 2017 Author Share Posted April 11, 2017 (edited) Hi, what's wrong with this now? No image upload, no error, no file in Network console. Thanks. //inside main btn onclick function $(function () { $(":file").change(function() { if(this.files && this.files[0]) { var reader = new FileReader(); reader.onload = imageIsLoaded; reader.readAsDataURL(this.files[0]); } }); }); function imageIsLoaded(e) { compImg = document.getElementById("compImg").value; containUp = document.createElement("div"); containUp.className = "img_descrip_wrap"; img = document.createElement('img'); src = compImg; img.src = src; $('compImg').attr('src', e.target.result); containUp.appendChild(src); document.body.appendChild(containUp); }; }; //close onclick function Edited April 11, 2017 by paulmo minor edit. Link to comment Share on other sites More sharing options...
Ingolme Posted April 11, 2017 Share Posted April 11, 2017 If that code really is inside the button click handler, you're not assigning an event to the file input until after the button is clicked. Event listeners should generally be attached in the global scope. Do you know what each line of that code does? Link to comment Share on other sites More sharing options...
paulmo Posted April 11, 2017 Author Share Posted April 11, 2017 4 minutes ago, Ingolme said: Hello, If that code really is inside the button click handler (it is) you're not assigning an event to the file input until after the button is clicked. But the input is assigned the onclick() function just like the other inputs... Event listeners should generally be attached in the global scope. Need help seeing this (if it's not the onclick handler). Do you know what each line of that code does? It seems that FileReader() function is retrieving the 1st value of array [0], in this case 1 file, and it's encoding the image in bytes with readAsDataURL, then the 2nd function applies source attribute and event handler (e), which I thought was the main onclick function, but from your reply it seems something's wrong here. Guidance appreciated, thanks. Link to comment Share on other sites More sharing options...
dsonesuk Posted April 12, 2017 Share Posted April 12, 2017 (edited) You keep repeating tbe same problem, IMG ELEMENTS DO USE A VALUE ATTRIBUTE, ONLY INPUTS USE VALUE AS A ATTRIBUTE, IF YOU KEEP RETRIEVING VALUE FROM A IMG ELEMENT IT WILL NEVER EVER WORK! GOT IT! VALUE ATTRIBUTE FOR IMG NOT WORKY, NOT VALID ATTRIBUTE FOR IMG ELEMENT. VALID ATTRIBUTE YOU REQUIRE TO GET IMG PATH AND/OR FILENAME IS SRC, THIS GOODY, THIS WILL WORKY. (1) Return imageIsLoaded function to original state, without createElement code etc, but keep $('compImg').attr('src', e.target.result); in there. Also I don't know if this was to refer to variable or typo for id selector, if variable it has rendered the variable useless! Because now surrounded with quotes it refers to element called 'compImg' which does not exist. If typo it should have ‘#‘ at beginning that identifies it as id reference and since we are removing attribute coding it should refer to that $('#compImg').attr('src', e.target.result); Edited April 12, 2017 by dsonesuk did edit and it removed half my content, and i'm not going to repeat well done ypos Link to comment Share on other sites More sharing options...
dsonesuk Posted April 12, 2017 Share Posted April 12, 2017 (2) Once the description is entered in TEXT input, you have all you require for populating the created img, and created paragraph. The SRC (encoded) of preview image for created img element, and the VALUE of input type text (you might want to consider textarea form element) for paragraph textnode. (3) Append these created elements to created div container. (4) Store these src and values in array/s or object array (depending which way you want to go with these), Then pass these arrays through to localstorage. The creating of elements, retrieving img src, description text value, will be all carried out by event of clicking 'Load' button. Link to comment Share on other sites More sharing options...
justsomeguy Posted April 12, 2017 Share Posted April 12, 2017 Also, you're never going to see a request in the network console because you're not sending the file over the network, everything is being done in the browser. You're reading the local file and updating the page, not sending it to a server. That's why there's no request to a server. 1 Link to comment Share on other sites More sharing options...
paulmo Posted April 12, 2017 Author Share Posted April 12, 2017 (edited) 18 hours ago, dsonesuk said: IMG ELEMENTS DO USE A VALUE ATTRIBUTE Hi, you meant to shout img elements don't use a value attribute. Revised some things below. //nested in btn onclick function $(function () { $(":file").change(function() { if(this.files && this.files[0]) { var reader = new FileReader(); reader.onload = imageIsLoaded; reader.readAsDataURL(this.files[0]); } }); }); function imageIsLoaded(e) { compImg = document.getElementById("compImg"); var count = 1; src = compImg; img.src = src; $('#compImg').attr('src', e.target.result); $('src').append( $(container)); //like this? return function() { //return to orig. state? count++; } }; }; //close onclick function Quote Also, you're never going to see a request in the network console because you're not sending the file over the network, everything is being done in the browser. Thanks for clarification, I see that now. Edited April 12, 2017 by paulmo responding to multiple replies. Link to comment Share on other sites More sharing options...
dsonesuk Posted April 12, 2017 Share Posted April 12, 2017 38 minutes ago, paulmo said: Hi, you meant to shout img elements don't use a value attribute. Revised some things below. What should I do now? YES! that's it AND No! that is not how that code was originally it was or should have been similar to $(function () { $(":file").change(function () { if (this.files && this.files[0]) { var reader = new FileReader(); reader.onload = imageIsLoaded; reader.readAsDataURL(this.files[0]); } }); }); function imageIsLoaded(e) { $('#idOfImgElement').attr('src', e.target.result); }; BUT! With $('#idOfImgElement').attr('src', e.target.result); changed to $('#compImg').attr('src', e.target.result); AND it should NOT be nested within any event functions $(function () {...}); Acts like onload of completely rendered page, if you place this within any event function, because that function only runs after a specific event AFTER the paged has fully loaded, it misses its chance to set the onchange event to convert the img src when the file loading input has changed, which would then read file, ignoring path (for security reasons) , and return as encoded img src, it runs at same time a function to apply this encoded src to img src with id 'compImg'. So this code is separated from my final code you said had working, that added input text to description array, which was stored in local storage. You now do same process for image, but instead of retrieving image src from text or file input (as mentioned the file input will only show filename not the path to that image for security reasons), you retrieve the src from the preview image encoded src (id="compImg") to add to array, then add img array to localstorage. Link to comment Share on other sites More sharing options...
paulmo Posted April 13, 2017 Author Share Posted April 13, 2017 ok this is outside the btn onlick function now, still trying to figure out how to get file upload image on the page...you said take element etc. out of there but how else to get this on page or even troubleshoot where file is (or is not) going in dev console? Thanks. }; //close onclick function //File Upload $(function () { $(":file").change(function() { if(this.files && this.files[0]) { var reader = new FileReader(); reader.onload = imageIsLoaded; reader.readAsDataURL(this.files[0]); } }); }); function imageIsLoaded(e) { var container = document.createElement("div"); container.className = "img_descrip_wrap"; compImg = document.getElementById("compImg"); var img = document.createElement('img'); src = compImg; img.src = src; $('#compImg').attr('src', e.target.result); container.appendChild(compImg); //tried src, img... document.body.appendChild(container); }; </script> Link to comment Share on other sites More sharing options...
justsomeguy Posted April 13, 2017 Share Posted April 13, 2017 The forum decided to eat my entire post. src = compImg; img.src = src; You're setting the src of an img element to be another img element. Shouldn't that be this: img.src = compImg.src; Is that what you're trying to do? Create a new img element and set the src of it to the src of an existing img element? For this part: container.appendChild(compImg); compImg is already on the page, is that what you want to append to the new div? Don't you want to append the element you just created? Otherwise you're not doing anything with the new element. Other than that, I would suggest using console.log statements or setting breakpoints to pause the code and look at the values of things. For example, I would check that e.target.result is something that belongs as an img src. Link to comment Share on other sites More sharing options...
dsonesuk Posted April 13, 2017 Share Posted April 13, 2017 (edited) You ignore everything I told you do? And placed create image code inside imageisloaded function? You will end duplicating code? The btn onclick will do all that, and it will also act as confirmation before comitting and adding both image and description together to the page, array and finally to localstorage. If you add it to imageisloaded function you risk images and description being processed out of sync to each other and not being tied together on page or arrays. (1) Get preview image to show and work if it does not already. (2) Use the onclick of id 'btn' we already had working to retrieve preview img src and description, for creating and adding to page, store in array/s and add to localstorage. The description part was already sorted, you just had to sort the image part to run along with description processing, which will be similar. The only difference is you are reading the src of preview img element. Edited April 13, 2017 by dsonesuk Link to comment Share on other sites More sharing options...
paulmo Posted April 13, 2017 Author Share Posted April 13, 2017 (edited) The image preview is actually working. I made the mistake of working from a closely-named copy file, while leaving the old file up in the browser, so I wasn't seeing changes. What's happening now is immediately after selecting file, it's rendered on the page. I need it so that it only renders when submit (load) button is clicked (like the other inputs), and compImg will get rendered nicely in the container img_descrip_wrap (it does do this with element created in imageIsLoaded, but only after subsequent file selections, current file selection is always outside the container). So do I create another document.getElementById('btn').onclick = function() {, after imageIsLoaded(e), calling imageIsLoaded(with or without e), somewhere in the onlick function? function imageIsLoaded(e) { compImg = document.getElementById("compImg"); //don't need value $('#compImg').attr('src', e.target.result); }; </script> Also, some general observations...in my onclick function that puts URL image on page, image does not render without .value here (dsonesuk?): var val = document.getElementById('idImage').value; whereas this does render, from imageIsLoaded(e) function: compImg = document.getElementById("compImg"); Also, in onlick function that puts URL image on page img.src = val.src doesn't work, but it does work in imageIsLoaded function var val = document.getElementById('idImage').value; //need value var img = document.createElement('img'); //img.src = val.src; doesn't work here src = val; img.src = src; container.appendChild(img); document.body.appendChild(container); Thanks for continued support. Edited April 13, 2017 by paulmo formatting borked Link to comment Share on other sites More sharing options...
dsonesuk Posted April 13, 2017 Share Posted April 13, 2017 You cannot use 'compimg' because its an id ref, you can't use the id within container with 'img_descrip_wrap' class, because as multiple 'img_descrip_wrap' are created along with images, and paragraphs, the id references will also be multiple which IS NOT ALLOWED, trying to access single element or manipulate a element with this id will fail. The file input will not provide a usable image file on its own, you would need server language to upload image to a directory and provide path and file name to that file. This code create encoded copy of image so you not need to download, just use encode url of preview image, that is what the image that shows will provide. If you do not want to have preview image send the encoded url to a hidden type input, and access that value instead. Link to comment Share on other sites More sharing options...
dsonesuk Posted April 13, 2017 Share Posted April 13, 2017 You are using so many, different, renamed id references I don't have any clue what they actually refer to anymore so I can't comment, they could be out of scope, not img, not input, multiple id when they should be unique, all these cause it to fail. Link to comment Share on other sites More sharing options...
paulmo Posted April 13, 2017 Author Share Posted April 13, 2017 Posting the updated script should help (minus getItem localStorage to element/container, that was just an exercise). It's all working great except the file upload needs to go in the container on btn submit (load), not as a full image on file select. Thanks in advance for helping. <body onload = "lsCheck() ;"> <form action="#" onsubmit="return false"> Upload image <input type="file" id="upld" value="Choose file"/> <img id="compImg" src="#" onClick="this.select();"/> or URL: <input type="text" name="image" id="idImage" value="" onClick="this.select();"/> <br><br> Description: <input type="text" name="des" id="idDes" value="" onClick="this.select();"/> <br><br> <input type="button" id="btn" name="submit" value="Load" /> <br><br> </form> <script> // checks localStorage function lsCheck() { lsData = []; if (localStorage.desSet) { //localStorage.removeItem(desSet.splice(0,15)); lsData = JSON.parse(localStorage.getItem("desSet")); //Map replace for loop var lsDataMap = lsData.map(function(mapResult) { return mapResult; }); console.log(lsDataMap); } var valDes = lsDataMap; //use lsData[i] in for loop } document.getElementById('btn').onclick = function() { //image on page var container = document.createElement("div"); container.className = "img_descrip_wrap"; var val = document.getElementById('idImage').value; //need value var img = document.createElement('img'); //img.src = val.src; doesn't work here src = val; img.src = src; container.appendChild(img); document.body.appendChild(container); img.onclick = function () { window.open(src); } //descriptions from form submit (below image) var valDes = document.getElementById("idDes").value; var des = document.createElement("p"); var tex = document.createTextNode(valDes); des.appendChild(tex); container.appendChild(des); document.body.appendChild(container); // append current descrip. value into array lsData.push(valDes); // set entire array to localStorage localStorage.setItem("desSet", JSON.stringify(lsData)); //remove: position, # of items. //lsData.splice(1,3); //remove entire key //localStorage.removeItem("desSet"); }; //close onclick function //File Upload $(function () { $(":file").change(function() { if(this.files && this.files[0]) { var reader = new FileReader(); reader.onload = imageIsLoaded; reader.readAsDataURL(this.files[0]); } }); }); function imageIsLoaded(e) { compImg = document.getElementById("compImg"); //don't need .value $('#compImg').attr('src', e.target.result); }; </script> Link to comment Share on other sites More sharing options...
justsomeguy Posted April 13, 2017 Share Posted April 13, 2017 This is why it runs when you select a file and the file input field changes: $(":file").change(function() { If you want a button to control that then use a click handler for the button and get the file input by ID to get the list of files. Link to comment Share on other sites More sharing options...
dsonesuk Posted April 13, 2017 Share Posted April 13, 2017 You need the upload for images on a users computer, because it creates encoded image source of the actual image, without the need for downloading and storing on website server. You need the text input for the url of website image url, where you copy the image location, and paste. Now you need to identify which is required to be displayed and stored, by checking both the upload preview image and URL input, then whichever is not empty, that is the one to process. After this and the description have been processed appended to array, stored in localstorage you need to reset file upload input AND preview image src to "", along with URL input, ready for the next image and description. You also might want set up if focus of either input, reset the alternative automatically, also make sure one of both image inputs and description input are not empty, before processing, and clear both inputs, image if reload of page takes place. Link to comment Share on other sites More sharing options...
paulmo Posted April 14, 2017 Author Share Posted April 14, 2017 Thanks JSG for the lead that change(function() controls loading the file when file is clicked. How to integrate that with btn onclick function (handler) eludes me at this point but I'm going to try to get some help with that. Re: "get the file input by ID to get the list of files" -- the file input ID compImg to get a list of what files? dsonesuk, "reset file upload input and image src to "" sounds interesting. W3S example shows appending .reset() to form id. Whi ch function would I put that in? I understand checking inputs and description so not empty. What purpose would focus() have here? Right now the images do get cleared on page reload. Link to comment Share on other sites More sharing options...
dsonesuk Posted April 14, 2017 Share Posted April 14, 2017 You don't need to integrate loading change with btn click, it job is to on change of file selection, create encoded image, and you then retrieve that data to show and store. So as already suggested leave as is. The button click will retrieve data from either preview img element, (or instead a hidden input if you choose) storing encoded image data IF upload option is used, ELSE retrieve the URL input data. Both would have to be checked to identify which option is used, as in none empty encoded image data src or none empty URL input value AND assign whichever used to a variable for processing. After all processing is taken place within button click event function you need to clear all values and/or src of preview image encoded data, but note that the file upload input retains the filename value even after reload as it is different from a ordinary text input, so using .value=""; won't be enough, and if reset() used it will need to be initiated within click event function after processing has taken place. The focus() can be used if the user changes mind or made mistake in chioce of image retrieving option, as in when the user selects the alternative option it will clear the previously filled input AND possibly src of encoded image data. Link to comment Share on other sites More sharing options...
justsomeguy Posted April 17, 2017 Share Posted April 17, 2017 file input ID compImg to get a list of what files? The file input ID upld, to get the list of selected files. That's what you do here: if(this.files && this.files[0]) But if that is going to run on a button click, then this will not refer to the file input, so you need to get it by the ID and then check the file list. Link to comment Share on other sites More sharing options...
dsonesuk Posted April 17, 2017 Share Posted April 17, 2017 There will always be 1 file listed, the current file you selected, but since you are not uploading the selected image, its pointless referring to this, as you will be using the encoded data of the selected image that is returned by this code and used in the preview image with id 'compimg' attribute src, which is what you should refer to. Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now