So we can add products
and we can edit products.
In both cases,
we can also choose an image and upload an image.
And that's now the part
where I want to improve the front-end a little bit.
I want to make sure that if we do choose an image here,
we show a little preview next to this image picker
so that we can see which image we actually chose,
and we can visually confirm
that this is the image we want to upload.
Now, of course,
this is also something we did before in the course,
and I will basically apply exactly the same approach
as I did before in the course.
I'll use some front-end JavaScript code,
some browser side Java script code,
to listen for the change event
on this input here, on this file picker,
which will trigger whenever the user does change
the picked file.
And then once that change event fires,
I check if a file has been picked,
and if a file has been picked, I configure a URL,
a preview URL to that file,
which is still locally on the visitor's computer,
but nonetheless, we can create a preview URL to that file,
and then I will add an image or show an image element
that points at that URL, that uses that URL.
That's the plan.
And for this, back in our code,
we got a couple of things to do.
For example, in our product form template,
in our product form EJS file,
We have to make sure that we do have a preview element,
a preview image element,
which we can use to show the image preview.
And I want to show that next to my input here,
and therefore I will actually wrap this paragraph
that holds my label and my file input
with another div, to which I'll add a class,
or an id actually, of image upload control.
Name is up to you of course,
but I'll add that div for styling reasons,
because I want to add an image side by side,
or I want to display an image side by side
to this label input combination.
So I'll move this label input combination in this paragraph
into this div.
And then below that I'll add a image tag,
which has a source and an alt attribute.
And that should now be set with help of JavaScript.
Now the alt text can be selected image, something like this,
but the source, of course, should be set with JavaScript.
And of course it should also not be visible all the time.
Now, before we write the actual JavaScript code, though,
I want to work on the styling here.
I want to make sure that we do position the image
side by side, to the label input combination.
And for this, of course, we need to go to the CSS files.
And now we got a decision to make.
We can add this code for styling this image preview
into the product CSS file,
since we are dealing with products,
the image preview will be for a product.
We could add it to forms CSS since we, of course,
are working in a form.
And ultimately it's up to you, what you prefer.
You could also add a brand new file,
which is a administration specific CSS file,
which you only include on the administration pages.
I will simply go for forms CSS though, and there,
I want to target my image-upload-control by id.
So this div I just added with that image upload control id.
And there, I want to add display flex
so that the paragraph in that div, this paragraph,
and this image, are positioned in the same row.
That's what Flexbox does out of the box, as you know.
And then with the line items center,
we can center those items vertically,
since that's the cross access of the Flexbox row.
And this will then ensure that the items,
the label input combination and the image preview,
are centered on the same horizontal line, so to say.
Now we also of course need more styling though.
I do want to restrict the width of my input
in that image upload control div.
So of that file picker.
it should not take a lot of width
because of course it doesn't need a lot of width.
If you have a look at it, it's not like the other inputs.
And therefore I will actually restrict
the width of this input
in the image upload control div to, let's say, 15 REM
and set this as a max width maybe.
And then of course you also want to style the image.
So inside of this image upload control div,
I want to target the image element,
and there make sure that we got the proper styling as well.
That means that I do want to give that,
let's say a width of 4 Rem and a height of 4 Rem.
So width 4 Rem, height 4 Rem,
and you can play around with these numbers
to find a good width and height.
And I want to set object fit to cover
to make sure that this is not distorted,
but instead cropped.
And I'll give it a border radius of border radius small
so that we have some rounded corners.
Now with that, if you save everything and reload,
we got this image here,
and of course we got no image at the moment,
but we can see where the image will appear later.
Now, by default at the beginning,
it should not be visible though.
I only want to display this image once we get a image
and therefore I'll set display to none here
on that selected image.
So that from the start, it's not there,
it will only appear once we chose an image.
So that's now the image preview element and the styling.
Now we need the JavaScript code to add the logic.
Now for this, of course,
we need to go to the scripts folder in the public folder
and add a brand new scripts file.
I'll name it, image-preview.js
since that's what this file will help us with.
And in this file, I, first of all,
need to get access to this input element
so that we can add an event listener to it.
And then to this image preview element,
which is currently not shown on the screen,
so that we can set the source of that element
and show it once we get a image.
So I need the image picker element, you could say,
and we get that with document, and then let's see,
how can we select this file input?
There are various ways of doing that.
I would say we can, for example,
select the input that we find in an element
with the id of image upload control.
Alternatively, we could simply select it by id here
or in a lot of other ways as well.
To practice different ways of selecting elements,
I will go for the query selector,
which we haven't used thus far in this section,
and I'll start by selecting the image upload control div,
so the element with that id.
And this is the id CSS selector, so we use that here
because querySelector wants CSS selectors in its argument.
And then I'm interested in the first input.
And hence, we can write this CSS selector
to select this input in the div
with this id with help of querySelector.
Now, I don't just need the image picker element.
I also need the image preview element, which is the image.
And of course we can use a similar approach
and just copy that.
And instead of the input, select the image.
Again, alternatives would have been to use the id
or any other kind of CSS selector,
but this should also do the trick.
Now we need to add a function that should be triggered
once the image picker fires the change event.
So once the user changes the picked image.
And I'll name this update image preview.
That sounds like a fitting name for this function,
which describes what it will do.
So we'll add logic to this function in a second.
For the moment I'll just wire it up to the change event
on the image picker element.
So we use that image picker element
and call add event listener.
And the event I do want to listen to
is the change event here,
which will trigger whenever the user changes
to pick the image.
And then as a second parameter value, here,
we point at the update image preview function,
which should be executed once a image was picked.
Now in that function, we can now extract an array
of all the files that have been picked, since theoretically,
you could configure the input elements
such that you can select multiple images,
though that's not what we support in this website here,
but we can get a list
of all the files that have been selected
by reaching out to the image picker element,
so this file picker input element,
and accessing the files property there.
Now this is an array, but in our case,
it will always be an array with exactly one element.
Nonetheless, I want to check if no files have been picked,
so if files is maybe not truthy, if it's falsey,
or if file's length is equal to zero,
which means no image has been picked.
This could be the case if previously a file was picked
and the user now deselected that.
In that case, if no file was picked,
I want to return and not continue
with any logic I'm about to add after this if check.
But in addition,
I also want to reach out to my image preview element,
so to this image element,
and access the style property there
and set the display style to none, to hide it again,
in case it was shown in the meantime.
If you make it past this if check,
we know that we got files, and in that case,
my picked file is actually the first and only file
in that array of files,
since in this website, we only support picking one file.
And then we want to construct a URL to that file.
Now, important, as mentioned before,
this file lives on the computer of our visitor,
not on our server.
Still, JavaScript, browser side JavaScript to be precise,
gives us ways of constructing URLs to local files
that have been provided by the visitor of our site
as the visitor did it here with the image picker.
We can create such a URL with the built-in URL class,
so that's a class built into front-end JavaScript.
And on that class,
we've got a static method called create object URL.
Since it's static, we don't have to instantiate the class.
We can just call this static method on the class,
as we did it with our own model classes
on the backend as well in the last lectures.
And to create object URL, we pass the picked file.
This will generate a URL that will work on the computer
of our visitor who picked that file.
Now this is the URL I want to set as a source
on the image preview element.
So there we can access the SRC property to set that source
and set it equal to that generated URL.
And then of course, I also want to make sure
that this preview element is visible.
So I will access the display style here
and show this element by setting the display style
of that image to block.
Alternatively, you could also set it to inline.
That doesn't matter.
The only thing that does matter
is that it's not set to none.
Now we need to make sure that this image-preview.js file
becomes active when we are on one of our form sites,
so if we are on the new product or update product sites,
and therefore we should go to new product EJS,
and there, before we close the head section,
add a script import, as we learned it,
by pointing at scripts
and then image dash preview js was the name,
and add defer to make sure it only executes
after all the HTML content here has been parsed.
And do the same for the update product EJS file
so that there, we also see a image preview.
Now with all that done,
if we save that and I reload the new product page,
if I choose a file here, let's say I'm adding a track pad,
I see a preview here.
So now I can add this product as well,
our great mouse alternative.
It helps you navigate around on your system
and it's all white.
Yeah.
So now we can add this product as well.
Click save.
And now we've got the magic track pad here,
the keyboard here, and yeah, these are super fancy products.
It's all the same.
Sorry, I just took photos of what I have in front of me,
but now we have these products here
and now let's also see if the preview works
if we are editing.
For this I'll pick the keyboard here, and that works.
And if I would save this,
you see it was also uploaded and replaced.
Also if I reload this page.
But of course here I want to go back to the track pad
Preview works, saving works.
This all looks good.
And that's how we can add such an image preview.