Jump to content

upload local file to page


paulmo

Recommended Posts

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 by paulmo
formatting
Link to comment
Share on other sites

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

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 by paulmo
minor edit.
Link to comment
Share on other sites

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

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

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 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

(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

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.

  • Like 1
Link to comment
Share on other sites

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 by paulmo
responding to multiple replies.
Link to comment
Share on other sites

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

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

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

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 by dsonesuk
Link to comment
Share on other sites

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 by paulmo
formatting borked
Link to comment
Share on other sites

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

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

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

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

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

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

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

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

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

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...