So now that we've managed to create our new Internet Computer decentralised app and we've managed to
get the frontend linked up and working, then it's time to actually make sure that we can persist the
data that the user types in, and figure out how we're going to do our backend using Motoko.
Now, if you didn't manage to get this working, don't continue.
Make sure that you go back to the previous lesson and get it actually up and running because none of
the things that we're going to be doing now is going to help this.
So if you don't see this running on your local host, go back to the previous lesson and try again from
the beginning.
You might have missed out something somewhere that's actually causing your problem.
But if you're seeing what I'm seeing, and you managed to get the Keeper app running on local host with
the frontend actually functioning, then we can proceed to the next step.
Coming back to our code, we're going to close down some of these files and go into our main.mo.
Now inside this, you've got the "Hello world" code, which is just there from the template, so we can
delete it entirely.
And let's go ahead and create our actor, which is our canister, again from scratch.
So I'm going to call Dkeeper.
I'm just adding D to all the decentralized apps that we're creating, but keep the naming that I've
got just so that when we do issue commands and stuff, we're all using the same thing and we're not
getting confused by some of these naming things.
When you create your own custom projects later on, feel free to name it whatever you want.
But for now, just continue and use the terrible names I come up with. Inside our new actor
we're going to create a new data type.
This data type is going to be of type: Note, and this is basically the way that we create a new data type
to represent the kind of data that will be stored in each of these notes.
And as you can see, it's just the title and some content.
So this data type is going to be pretty simple as well.
So you're going to write the type keyword and then Note, and then we're going to use an equal sign
and open up a set of curly braces.
Now we'll get to add the components that make up a Note.
So it's going to be a title, which is going to be of type, Text, and some content, which is also going
to be of type, Text.
Cap those off with some semicolons and now we've got a new data type created in Motoko.
The syntax can be a little weird.
It's a little bit different from JavaScript, how we would create new objects, but it's not too big a
difference and you can pretty much see what's going on here. Because we need to access this type from
the JavaScript side as well,
it's a good idea to add the "public" keyword to the front of it.
This way when we're writing our code in our index.js or inside our components, then we'll actually
be able to see this data type and be able to use it there as well.
Now next, we're going to create our new variable, which is going to be called notes.
And this variable is going to have a data type of a List, which is kind of similar to the arrays that
we've been working with in JavaScript, but also a little bit different.
And I'll point out the differences later on.
Now, the list is going to contain note type,
so to specify that in this data type, we have to write a List.List, and then open up some angle
brackets and say that it will contain <Note> objects inside this list.
Now we're going to start it off as an empty list for now,
so we'll just say List.nil and again, specify that it is going to be nil, but it's a nil <Note>()
object and then we add a set of parentheses and this will create a new list object.
Now you'll see a red underline here saying, "unbound variable List,"
and this is because in order to use some of its functionality,
so if we use list dot something, we're no longer using it as a type, but we're using some of its methods.
So we have to import it, basically.
So we can just copy that and then say import List from the Motoko base library and the list module and
now you can see those errors disappear.
So here we've basically created the equivalent of an array of Note objects, but in this case, it's
actually a list that contains objects
of type Note.
Now we're going to create our public function and our function is going to be called createNote and
it's going to allow us to send over some titleText from the JavaScript side when the user enters it
into the text field and also send over some contentText.
And once we've gotten hold of that, then we can create a new Note so we can say let newNote be of
type Note,
and we can use the = { to set it.
So we're going to set the title attribute to equal,
so notice here we've got equal when we're creating the newNote,
and here when we're declaring the type, we've got the semicolon to specify the data type.
So a little bit different,
just be careful.
And we're going to set the title attribute to the titleText that was sent over,
and the content attribute is going to equal the contentText that gets sent over.
And now here we've created our newNote from whatever data was added to the input when this method was
called from the JavaScript side.
And finally, what we have to do is to add this newNote to this list of notes.
And if we take a look in the Dfinity documentation, and we go to this List type, you can see that
we've used the nil to create an empty list.
And we're now going to use the push to add the newNote to the list.
And you can see it happens by pre-pending a value.
So it's going to get added to the beginning of the list.
And this is a little bit different from how we add to arrays normally where we normally append it,
so we add it to the end.
And this is going to come in as very important a little bit later on when we try to organize our various
Notes inside the Keeper app.
So we're using this push and in order to push an item onto the list, we have to specify two things.
One is the item that is going to be pushed into the list, and second is the list that you want to push
it on.
So this is actually a function from the List module. In order to call it
we have to first tap into the List module and then use .push and then open up our parentheses and
add the first item.
The newNote is going to be pushed onto the List and then comma,
and the list that we want to push it into is the notes list.
And let's just add some semicolons so that we make these errors go away.
Now, in this case, what we've done with this line of code is we've basically created a new list that
adds this new note to the beginning of the list of notes.
We haven't actually amended this list at all.
So in order to actually set this as the value, the new value of this list of notes, we have to use
that assign operator.
So we have to say notes := the new list that's created from this function.
And once we've done that, let's go ahead and add a Debug into this.
So let's import the Debug library.
And use Debug.print and then debug_show in order to print out what the notes list actually looks
like at this point.
So this is all that we have to do in our main.mo file in order to create a new note.
So notice we're basically doing CRUD here, right?
Create, Read, Update, and Delete.
And we were doing this whenever we built backends using MongoDB, adding new items to the database,
reading from the database and all of that.
So this is a really, really good example to get your head around how CRUD works using Motoko on the
ICP Blockchain.
So we've created it our Motoko file, but we have to link it up with our JavaScript. And where most of
the action is happening on the JavaScript side is inside the app.jsx.
So if you open it up, you can see there's a function called addNote() which gets triggered every time
the user presses this add button.
And that's because we created that component called CreateArea, which is basically this area,
and we have an event listener on that add button so that when that happens, we trigger this function addNote
.
And we went into this in a lot of detail when we learned about React.
So I'm not going to go into this too much.
If you want a quick review, I again really strongly recommend that you take the React module before
you proceed so that everything makes more sense.
But if you have done the React module, then let's just plow on.
So this function is what we're going to have to modify a little bit in order to get this createNote
to be triggered and to pass it the things that it needs.
So in order to get hold of anything in the main.mo file, we have to import it into our jsx file.
So I'm going to say import, and then it's going to be a set of curly brackets,
and inside these curly brackets, I'm going to refer to the name of my canister which is going to
be to dkeeper. The canister name is specified in the dfx.json.
And because we created a new project called dkeeper, both the main folder and the canister are called
dkeeper. And the location is going to be from and then it's going to be ../..
/../declarations, and then it's going to be dkeeper folder.
And this relative path corresponds to... Every ../ is an exit,
so going up one level.
So here we've got three of these
so we're going up three levels.
So from the app.jsx, into the src folder, from the srcfolder into the dkeeper assets, and then
from here into this final level so that we're here. And then we go into the declarations folder and we
go into the dkeeper folder, so that we can get access to all the things which are public in our main.mo.
Now at the moment, you'll only see the previous function from when we built this brand new Hello World
app, which contained that greet() function.
But if we go ahead and run a "dfx deploy", it will be able to create the required bridge to allow our
JavaScript code to call these Motoko functions.
And you can see that here,
we've now got our createNote that takes two text inputs and returns nothing.
So coming back here, we can then access it using our module name.
So inside the addNotes function, when we're triggering set notes basically to update the state of
our notes constant,
just before we return, we're going to call that function.
So we're going to say dkeeper., and we're going to tap into that method name, and it doesn't always
load it up for you,
so it might be worth just actually copying it from here or from here,
it doesn't really matter as long as you've got it spelt correctly.
And then we have to provide two arguments which both have to be strings.
And in JavaScript, we're going to have to make sure that the order that we add in the arguments matches
with the order that we created in our Motoko side.
So the first thing we add is the title and the next is the content.
So in here we're going to tap into this newNote that's created on the frontend,
and we're going to tap into, firstly, its title,
and secondly, it's going to be the newNote.content.
And the reason why they have these attribute names is because in our createArea, we've defined how
the notes are structured and they've got two attributes: title and content.
So I'm just keeping it the same everywhere for consistency sake.
So in this case, we're tapping into the title and the content that gets created on the frontend, and
I'm sending that over via the createNote back over here so that we can create a newNote on our back
end.
And with just those few lines of code, we should have now be able to get this to work.
What I'm expecting to happen is when I create a new note and I click add, not only does the frontend
update because I'm using the usedState to update the notes constant to include the newNote that was
created,
but also I'm expecting a print statement to occur somewhere in here, to show that that newNote has actually
been created on the back end and this List of notes has been updated.
So let's try it out.
So if you haven't already dfx deployed, go ahead and do that, because that's going to be really important
to make sure this code actually can be reachable.
And once you've done that, let's refresh our
Keeper app and let's write a new note, which I'll call Note1.
Let's hit Add, and you can see the frontend updates immediately because that's happening through React.
But the most important thing is to make sure our backend actually registered correctly and that this
debug statement actually got called.
And if you look in here, the terminal where you had the dfx start running, you should see that the canister,
so this to dbank canister, sent the message where it printed out what is currently inside this notes list,
and it has the content of this, and the title of this, which matches exactly with what we typed in there.
Now we've managed to actually get our backend to work and to complete the C aspect of the CRUD, to be
able to create new items on our backend and store that inside our list, which is called notes.
Now in the next lesson, we're going to move on to the R of CRUD.
So we're going to be able to read from these notes and update them in here so that when we refresh it,
they don't disappear.
So for all of that and more, we'll see on the next lesson.