All right.
So this is the third and final part
of implementing the functionality of uploading or recipes.
And let's start by adding yet another recipe
so that I can show you something that is still missing
from our controller.
So actually, two things.
So, let's say this one here, test avocado.
Okay.
Just so we have a different name and watch what happens here
to the URL as we upload this recipe.
So actually nothing will change.
So, take a look at that.
Okay.
So recipe was successfully uploaded
and we also still need to remove this window.
Right?
But anyway, here is the recipe that we just uploaded
but the URL did not change.
And also it did not yet add this new recipe
to our bookmarks, okay?
So of course it is bookmarked,
all right, as you see here
and as you can also see down here.
But we didn't yet rerender this bookmarks panel, right?
So there are two things that we need to fix.
So we need to rerender this bookmarks view
and we also need to change the ID here in the URL
because watch what happens if I reload this page now.
So then we are back to the old recipe that was there before.
So, because that's the recipe that is associated to this ID.
So let's go back to our controller and fix these things
and also put back here, toggling the window.
So, let's do that right here
after displaying the success message we also want to render
the bookmark view.
And so that will then basically add this new element
to the bookmarksView.render.
So model.state.bookmarks.
Okay.
And we are not using update here
because we really want to insert a new element.
And for that we use always render and not the update method.
Now, the second thing that we wanted to do
is to change the ID into URL and for that,
we can use the history API.
So let's say change ID in the URL.
So we can say window.history.
So that is the history API of the browsers.
And then on this history object,
we can call the pushState method.
And so this will basically allow us to change the URL
without reloading the page.
Now, pushState takes three arguments.
And this first one here is called a state
which doesn't really matter.
You can just specify null.
Then the second one is the title
which is actually also not relevant.
So we can just use an empty string.
And then the one that actually is important
is the third one, because this one is actually the URL.
And so here we can simply put the hash
and then the ID that we want to put onto the URL.
So that is @model.state.recipe.id.
And that's actually it.
And we could also do all kinds of other stuff
with the history API, like for example going back and forth
just as if we were clicking the forward
and back buttons in the browser.
So we could do like this.
Of course, it doesn't make sense in this situation,
but maybe in some other situation you
might find this one helpful.
So automatically going back to the last page.
So that should work now but let's not test it yet
because the next thing that we want to do
is to refactor these to our methods here,
these two functions.
So getJSON and sendJSON are almost the same right now.
And so we can basically put them together just
in one function called AJAX,
because both of them are being done
for doing an AJAX request.
So just like this.
And in this one we'll receive the URL
and also the upload data
but we will set this one to undefined by default.
And so with this, when we call this AJAX function
with only the URL, then of course there is no upload data.
And then in that case,
we can simply define the fetchPro as only this.
So let's actually do that.
So conditionally defining this fetchPro variable.
So fetchPro and let's test if uploadData does exist.
So if it does exist, then fetchPro should become this.
So lets grab that, put that here.
And otherwise, it will simply be this.
And that's it.
Now of course I could have used an if else statement,
but then I would have had to declare this here
as a, let variable outside
and then change that variable in both the blocks.
And that's not really nice.
And so now we can, basically copy everything else here.
And we don't need this one anymore
and this should go all the way to the top.
And that's actually it.
So lets comment this one out.
Just one final look, but everything looks good here.
And so here now we can no longer import this one.
But let's just keep it there.
And we simply import AJAX.
So here and here,
and then down here for upload the recipe,
the same thing.
Okay, so let's try that.
And we see that we still get the recipe.
We also get to search.
And now finally, let's add another test23 recipe here.
Let's just change it up a little bit.
And now again, take a look what happens to the ID here.
So, you saw that it actually changed.
And so, now the idea for new recipe
is exactly that one that we have here.
And also, it should now be in your bookmark
and indeed it is.
Okay, and so now if we reload this page, then you see
that we are back at this recipe that we just created.
Great.
But now finally, let's use our keys
or key in order to actually mark this recipe here
as our own recipe by displaying like a small icon here.
And so for that, we need to attach
our key to all the API queries.
So, we can add the key to this one here,
simply by adding the key and of course also to this one.
So the one which has the ID.
So again at the end, question mark and then the key.
Okay, so let's simply get this one here.
So...
This one is for the search results.
Let's add this here.
And here we already have a parameter.
So here, it is then and.
So, search &key, but then
Yeah, for this one.
So for loading the recipe, there is nothing yet there.
And so we can simply add our KEY like this.
And so now by adding this KEY,
especially in the search results,
it will then load all the recipes including the ones
that contain or own key.
So if I search for avocado now
because I have, well not here in the demo, but in this one.
So I created a recipe which contains avocado.
And so if I search for avocado now
that should then contain this recipe that I just created.
All right, now we now want to mark this
as our own recipe again,
here in the search results and also here.
And so let's do that.
And just as a side note again,
if you're using your own API key
then of course you will not see this recipe here
because this recipe is linked to my API key.
So as we see right here.
So this is the key that I am using.
All right, and the same hear in the results.
So here in all the results you will see
that my own one has the key.
So this first one,
right, so TEST AVOCADO, it has my key,
but the other ones of course do not.
But anyway, let's noW go to the recipe view
and also the preview view.
So the one responsible for these results
and add the logic there to actually display
that small icon there.
So, we don't need this one anymore and neither this one.
So recipeView and PreviewView.
So the code for that is somewhere there at the top.
Here it is.
So user generated.
And I guess, I wrongly deleted some code here earlier.
So let's go back to the HTML
and copy it back like this.
And now the indentation is messed up.
Then here, we need to replace that with icons once again.
And so now, all we will do with this element here
is to basically add the hidden class
if there is no key on the recipe,
but if there is a key then we will add no class.
And so then it will become visible.
Okay.
So that's simply, this.data.key.
So if there is a key, then we want to add no class at all.
But if there is no key, then we add the hidden class.
Okay, and now the same here in the previewView,
and actually here, we don't even have that yet.
So, let's actually grab the same code
from the recipeView because it is almost the same.
And let's just see that here to see
where we have to paste it.
Well, it's not here, so let's just paste it anywhere.
So let's put it right here.
And then it's probably gonna called
the preview user generated.
All right, or actually,
I think that it is inside of this div here.
So let's move that down a little bit.
Fix the indentation here once again
to make it easier to see
just like this.
All right, and so let's now try it out.
So, let's search for avocado here again,
and then here it is.
And you see that now we have this icon here.
While if we click some other recipe then, it's not there.
All right.
Now it's only still missing here,
but that is because we actually never added this key
to the search data.
So let's go back to our model.
And so here in the load search results,
this is where we create the data
that will then be put in the state.
Right, so state.search.results will become
these objects here.
And so that only contains ID, title, publisher
and image, but not the key.
And so let's grab this code
that we used here in order to add the key
to the recipe object and do that here as well.
Right, then here, we just have to change this to rec,
just like all the others here.
And then with that, we should be good to go.
So let's see.
Search for avocado one more time.
And now it is there.
Do you see?
Great.
So again, this one does not have the icon
while this one here, of course now has.
So right here.
Beautiful.
So this is just great.
Let me know close this here and create one final,
more real recipe here for pizza that we have been using
all the time.
So let me get rid of all of these weird bookmarks.
Oh, and you see that also here,
we now have this icon, right?
And so that's the beauty of using the same preview here
in the results and also for the bookmarks.
Right?
So that makes everything really more reusable.
What's happening here?
Okay.
Just getting rid of all of them
because these recipes are not really that interesting.
So let's now add a super pizza.
Then the URL, let's make it jonas.io.
So that's HTTPS, jonas.io.
Then let's go to Unsplash and grab some image from there.
Just to make this again, a little bit more real world.
So this one here looks quite nice.
So let's right click and copy image address.
Okay.
Then here, Jonas Schmedtmann,
prep time 75 minutes, two servings.
And here let's just use one kilogram of flour.
Then some tomato sauce and the rest doesn't really matter.
Okay, so it looks correct.
Let's upload it and it was successful.
And here we get the super pizza.
Let's see here, and indeed we can update our servings here.
We are in the Bookmarks.
And if I now search for pizza, then here, it appears right
at the first position with this beautiful image.
And so, that means that our application
is now basically finished.
I just spotted a small bug here.
So in this ingredient description,
remember that we replaced all the spaces.
And so with that we lost the space between tomato sauce.
So let's quickly go fix that
but I will not add another recipe.
So we're not going to test this.
All I will do is to fix this problem down here.
So instead of this replaceAll here, let's do it differently.
So I will split the string into multiple parts,
which will then return an array.
And then I will loop over that array
and trim each of the elements.
So map to create a new array.
Let's just call it element here
and then just return element.trim, just like this.
Okay, and so now if we add just something to test here.
So adding some spaces here and maybe here, and here.
And so you see this work just fine now.
Oh, now we have two recipes for some reason.
Not sure why that was, but you see
that the spaces that are inserted there, they are gone.
Okay, let's remove this one here.
I don't want to see that again.
And so, yeah, our application is now feature complete.
So if we check out our flowchart's part three,
everything here is now implemented and that's just awesome.
So congratulations for going through this huge,
huge project together with me and making it all the way
to the end.
And now in the next final lecture of the section,
I will just quickly show you how we can write documentations
for functions in order to make other people understand
our code a little bit better,
and then and just like before,
I have some final suggestions for you.
So like, features and improvements
that you will be able to implement
on yourself if you want to practice your skills.
So I hope to see you there soon.