All right. 1
So now that we've managed to add notes, be able to pull the notes out from Motoku backend, but 2
also we need to be able to delete them. 3
As I showed you earlier, you can delete them right now, but that's just on the frontend. 4
As soon as you hit refresh and we pull in all of our notes from the blockchain, it doesn't actually 5
change. 6
Let's fix that. 7
Notice here in our app.jsx, we've got the deleteNote function and all it does at the moment is 8
it updates our constant notes using the setNotes method to filter through all of the notes and check 9
for the one that has the index that's selected and then basically get rid of it from the previous notes. 10
That is why this frontend appears to work, but we need to link it up with our main.mo so that 11
when we actually hit refresh and we pull in these notes that it actually persists. 12
So let's go ahead and go into our main.mo and create this function. 13
So it's going to be a public function so that we can reach into it from a JavaScript, 14
and I'm just going to call it removeNote. 15
And in order to know which one to remove, I'm going to add an ID, which is going to be a natural number 16
because it's going to be zero or above. 17
And let me just add the semicolon so I get rid of this error here. 18
Now, in order to remove a particular item with a particular ID or index from the list that we've got 19
here, we actually have to do a little bit of a grunt work of our own because if you look through the 20
documentation as of right now, in 2022, there actually isn't a utility function for the list in Motoko 21
that allows us to just remove that index. 22
So we have to figure out how to do it using the available methods. 23
And to be honest, it took me quite a while to actually figure out how to do this, but I think I've 24
figured it out now. 25
So firstly, we've got a method here called take which returns the first n elements of a given list. 26
If the given list has less than n elements, then this function returns a copy of the full list. 27
So we supply two arguments. 28
One is the list that we want to take from, and the next is the first n elements. 29
So I've created this Motoko playground that you can find 30
if you look in the course resources. And if you head over to the URL in the course resources, you should 31
see something like this with the code that I've written here. 32
So I've got this variable called notes, which is a list of text elements, and then I add A, B, C, 33
D sequentially into this list. 34
Now remember that we said that push actually doesn't append, but it actually pre-pends. 35
So what do you think notes actually looks like? 36
Because we can test this. 37
If I go ahead and deploy, it's going to bring up a candid UI for me to work with. 38
And once that's done deploying, you can see we've got our three public methods here: drop, 39
getNotes and take. getNotes is going to show me what the current state of the notes is. 40
If I go ahead and click query, you can see that it shows us what the lists currently look like. 41
Now if we go ahead and click on UI, you can sort of see it a little bit better 42
how the structure of a list is different from an array, because when we add it using push, we start 43
out by adding A and then we add B and then we add C and then we add D. 44
It actually got added to the beginning, so pre-pended to our list. But also it doesn't look like a 45
list because they're not within the same hierarchical level. 46
In fact, it's almost like we've got an array that has many, many layers of embedding, and that's 47
why we had to convert it into an array before we send it over to our JavaScript so that we can actually 48
convert it out of this format and into a format that can be easily understood by the JavaScript. 49
This is the first aspect that's probably pretty weird that when we push items onto this list in the 50
order of ABCD, they actually go in in reverse order. 51
Now the next thing I want to show you is how this take function works. 52
So if I decided to take 2, what happens? 53
What do you think will be the new value of notes? 54
Because here I'm running take and I'm taking whatever I enter in candid here from the list of notes 55
and then I set the note to update it to the new list. 56
So if I go ahead and call this function and once that's done, then I click query, then you can see 57
what it's done is I've just taken the first two items from the list, which is D and C, remember, 58
they get added in in reverse order. 59
So our goal is to figure out some sort of way to implement a method, kind of like a remove at index. 60
So if we want to remove at index 2 basically in this case remove the B from this list, then how do 61
we actually use all of these methods that list provides to be able to do something like this? 62
Well, the first step is we're going to use that take. 63
So if we say take 2, what happens is we take the first two elements and we turn that into the list. 64
So we end up with D and C. Now next we can use this drop function which drops the first n elements 65
from the given list. 66
So in our case, if our list is the first argument, the second argument is how many elements to drop 67
from the list. 68
So let's try this again. 69
If we deploy and go ahead and click upgrade our canister, because our notes is not stable, it will just 70
be reset to the original. 71
And once that's done, 72
if we click query, you can see we've got our DCBA back. 73
So now if I go ahead and use the drop method and I say drop 2 and I call this method, then if I query 74
my getNotes again, you can see I'm left with B and A. 75
So how does this drop method work? 76
Well, if we say drop 2, it's basically going to take the first two elements and drop it from the 77
list. 78
So then we end up with whatever else remains, which is B and A. 79
So we've dropped the first two elements from the list. 80
Then to summarize, if we want to build this new method that doesn't exist, remove (index: 2) to 81
get rid of this B, then we have to combine our take 2, which takes the first two items, with our 82
drop where we drop 2. 83
Now that's going to end up giving us B and A. 84
So if we actually want to remove the item at index two, which is the B, then we have to drop the index 85
plus one in order to get A. 86
So then it will drop the first three items. 87
And through using a final method that we have on the list, which is called append, which allows us 88
to join essentially two lists together, we can join what was the result of the take (2) with the drop (2) 89
+ 1, and then we would end up with the result that we want D, C, A - B. 90
So we basically have to go through this slightly complicated process in order to be able to remove a 91
note from our list at the id which is the index that is passed in. 92
And I recommend, before you write the code to take a look at this playground. Just head over there, 93
deploy it, try out some different things and make sure you understand how drop and take actually works. 94
And then I want to set this to you as a challenge to write the function here so that when we get sent 95
over an id which could be 0, 1, 2, 3, basically the index of the item that needs to be 96
removed, 97
coming back to our slide here, if we wanted to remove B, then the index that you would get passed 98
is 2 because we start counting it 0. 99
So D is 0, C is 1, B is 2. 100
So when you get that 2, how do you actually remove that element at that index using those three methods 101
that we mentioned, which was take, drop and append? 102
Now, in addition to that, you'll also have to update the code in the app.js so that you actually 103
call that delete method and pass over that ID, which is going to be the index. 104
And if you manage to do all of that, then when you head back to the Keeper app, you should be able 105
to delete your notes and when you refresh they should not reappear. 106
So this is the challenge I'm sending you. 107
It's quite difficult. 108
Have a go, see if you can do it. 109
And then if you can't, or if you want to watch me walk you through it, then head back over here and 110
we'll do that. 111
Pause the video now. 112
All right. 113
So the first thing we said we're going to do is we're going to take our list, which is our notes, 114
and we're going to take the number of items that correspond to the ID that we want to remove. 115
To do that, we're going to use the List.take. Notice previously 116
every time we use the method from the list type, we've always had to use List.take and this List 117
.take expects two arguments: 118
one is the list you want to take from, 119
second is a natural number that corresponds to how many items you want to take from it, 120
so the n. Our list is notes and we want to take the index using this ID that we get passed. 121
Then I'm going to set it to equal a constant, which I'll call listFront because this will be the new 122
beginning of our list. 123
And then I'm going to create a listBack which is going to be created using list.drop. 124
So we're going to drop the list notes and we're going to drop the number that corresponds to the id 125
that we get plus one. 126
If this doesn't make sense to you, then just simply try it out. 127
Try it out using that playground and see what you actually get to be able to understand it. 128
But basically we're going through this three step process in order to remove an item when we're sent 129
the index of that item to remove. 130
The final step is we're going to reset our notes 131
so using that := sign, we're going to set it to the List.append and we're going to append 132
the listFront to the listBack. 133
And now through these three lines of code which you could if you want to simplify, but I think it's 134
easier to understand it when we split it out, then we achieve this remove at index functionality. 135
So we get sent the index and we use that index to update our notes to exclude that item by going through 136
this take and drop process. 137
And once we've done that, then we have to go back to our app.jsx and we're going to leave the 138
setNotes as it is because that's just going to handle the frontend and make things happen immediately. 139
But in addition, we're going to tap into our dkeeper and we're going to call that method that we created 140
just now, which is removeNote and we have to parse it 141
the value of the id that we get in this function. 142
Remember, that id comes from the index, which is indexed to correspond to the note that we want 143
to delete. 144
Finally, let's just cap that off and hit save and let's deploy our canister again. 145
Once that's done, let's head back over to our Keeper app. 146
Let's refresh. 147
And because we've redeployed our canister, our notes have been cleared. 148
So let's create our first note. 149
Add it. 150
Notice that it appears. 151
And then. 152
Now let's add another note. 153
And now I'm going to delete this first one so it immediately disappears. 154
And that is because of these lines of code. 155
But then if I refresh, notice how it doesn't reappear. 156
And that's because we're pulling it using the fetch data, 157
this removeNote at id has already removed the deleted note so that when we query for the list again, 158
then it doesn't show up in there. 159
And this way we've managed to implement the backend for our keeper to be able to add notes, to be 160
able to view them and have them persist, at least as long as we don't reset our backend. 161
And then to be able to delete them when we don't want them anymore and for that to persist as well. 162
Now, there's one final thing. 163
As you noticed, whenever I deploy or whenever I upgrade my canister, my notes get cleared. 164
And we can show that by updating something in the code. 165
Because remember, when you hit deploy and your code actually stays the same, it doesn't actually reset 166
the code. 167
So let's just go ahead and add a Debug.print to add a inconsequential line of code. 168
Now because this has updated the code of our main.mo, 169
if I go ahead and run dfx deploy, then it's actually going to force this code to upgrade our canister 170
which means this note's variable gets emptied out and gets to start from the beginning. 171
So now if I go back to my localhost, I hit refresh, 172
you'll notice that all the notes will disappear. 173
But we have one trick up our sleeve, and you've got it. 174
It's that stable keyword. 175
By turning this into a stable variable, 176
our list now persists across upgrades, which means that we've basically got a permanent storage solution 177
for our dkeeper app. 178
And now not only do we have a backend, because if I go ahead and hit deploy and I hit refresh, firstly 179
they don't disappear because we've got that storage on our backend. 180
But now if I go into my main.mo, I change the code significantly. 181
So delete that line for debug or add a line for debug, 182
basically either way forcing it to update my canister when I do dfx deploy. 183
So even though everything has now been upgraded and this code has now been refreshed, it doesn't matter 184
because if I go back once it's done and I hit refresh, all my notes are persisted. 185
It's as if I have a database in the backend, but I didn't really have to do anything other than add 186
that one stable keyword. 187
And that's something I think is super fantastic and really, really interesting. 188
It really means that we don't have to think so much about databases and getting things in and out. 189
And this is a really, really incredible way of writing code and creating applications. 190
So I hope you enjoyed building this to dkeeper app and taking the React frontend to combine it with 191
a internet computer blockchain-based backend and now being able to persist this. 192
So the main takeaways from this module was to show you how you can actually create apps writing 193
Motoko on the ICP blockchain, but also incorporate beautiful advanced frontend, whatever it is you 194
want to do on the frontend using React, thus being able to take our web3 applications really into the 195
future and to be able to make it look as beautiful as any web2 application while retaining the power 196
of an application that runs on the blockchain. 197
I hope that was fun 198
and I'll see you on the next module where we're going to be creating our own cryptocurrencies and our 199
own tokens on ICP. 200
So for all of that and more, I'll see you on the next lesson.