Check out a free preview of the full JavaScript Design Patterns for Web Apps course
The "Rendering TodoList Items" Lesson is part of the full, JavaScript Design Patterns for Web Apps course featured in this preview video. Here's what you'd learn in this lesson:
Max creates a method, renderList, to display TodoList items on the screen. The Observer pattern implemented in the TodoList class will use the notify method to call renderList and update the DOM whenever the data changes. This lesson also implements removing TodoList items.
Transcript from the "Rendering TodoList Items" Lesson
[00:00:00]
>> Maximiliano Firtman: Something that we can do at this point, let's see in which order that we can do this. Let's try to fill the gaps here on the ad first, for example, we can actually do that. So first, this is when you click Add. Let's remember our UI. We are here, so we are clicking on this button, okay?
[00:00:24]
So, what are the steps that we need to execute to add something on the list? Should we turn to the list here? So should I take the value from the input? Validate the input, we already have a command for that. So what we need to do is we need to talk with our CommandExecutor.
[00:00:48]
That actually, where is it? In command? It doesn't appear in the oil complete. Why is that? Because it's in its own module, and I'm not exporting this. So you need to always remember to export everything you wanna make public to the outside of your module. So now, if I try this now, it appears there.
[00:01:15]
So return, and please remember to add the .js here on the import. So CommandExecutor.execute, and I need to pass a command. So I can create a new Command that the name is from the list of commands. ADD, of course, if you don't like this, we can just create first variable, cmd or command.
[00:01:43]
>> Maximiliano Firtman: And just do this. So we create a command, no arguments in this case. We could also think about maybe we could test the text as an argument, so then the command is not talking to the DOM and we decouple this even further. It's an idea to implement, okay?
[00:02:02]
So there are always several ways. So always, it's better to decouple as much as possible, okay? If it's not getting too complex, I think it's fine. Then when you delete, before deleting, I think it will be better to actually try to render something. Because first, maybe if I run this now, at this point, if I refresh, nothing will work probably, and probably, we have errors.
[00:02:28]
So the first error we have is on mixin. Let's try to solve this, mixins js, so let's see. Mixins is actually important here, because it's mixin, not mixins, at least in my case, okay? Refresh, okay, no more errors. So now, I'm adding something here, like finish, whatever, Add, and I'm getting error on commands.
[00:02:53]
Okay, let's go one by one. Commands is not defined. It says, okay, let's see. So on app.js, we are using commands here. What's a problem? I'm not importing commands, so it's not importing everything. And maybe you're thinking, why don't you use a star? Because that's not ECMAScript. We cannot use a star on an import.
[00:03:15]
So the way to solve that problem is to use export defaults on one side, and then you receive one object with everything inside. So I should add commands as well here. So now, we should know what it is. Okay, nothing happens. Okay, well, it's actually removing it from the list.
[00:03:39]
So it's removing my text. Maybe something is happening, but I'm not seeing anything on the screen, okay? Which is expectable, because I didn't render any data. So let's finish that part and then we add the delete. To render the list, there are many ways to do that, okay, so there are many ways to do that.
[00:03:58]
I will use the simplest way. That doesn't mean it's the best one, but it's gonna be the best one for us today. But we are not going to discuss performance, okay? So have my mind that we can improve that later. So I'm going to create within app.js a function renderLlist.
[00:04:16]
We're going to render the list. Quick question for you, when should we execute this function, renderList?
>> Maximiliano Firtman: In terms of the life cycle or where we should be running this? What do you think?
>> Speaker 2: On load.
>> Maximiliano Firtman: On load, well, on load it's an event that happens when everything is loaded, including iframes, images, and other stuff.
[00:04:50]
DOMContentLoad is probably what you meant, so it's better than load. So, yeah, unload is one. So anywhere here, like here, I can call renderList.
>> Speaker 2: Are there suggestion for notify?
>> Maximiliano Firtman: For notify, so let's try to dig into that. Notify is one of the methods that we have in a mixin that was an observer.
[00:05:13]
So trying to translate that notify answer from someone in the chat, I think he's talking about the observer pattern. So that means, remember, we have a list. The list is implementing the observer pattern that will notify all the observers about the change, which means, can we just talk to our TodoList here?
[00:05:42]
Get the instance of it, remember it's a singleton, and add an observer, and we can say, execute my renderList. So every time the list is changing from a data point of view, I wanna render the list again, okay? Make sense? Be careful, I'm not adding parentheses here. I'm not executing renderList right now, I'm passing renderList as an argument for the observer.
[00:06:13]
>> Maximiliano Firtman: Okay, make sense? Again, we can discuss performance. That's another situation in terms of performance in the DOM, but that's for another another version. So now, renderLlist, then we execute it the first time when you open the app. And by the way, every time you open the app for now, at least, it's always empty.
[00:06:32]
I mean, the list is always empty, and also when the list changes. So what I mean with that empty thing? I mean that maybe we don't need this one, because the list is always empty. But maybe you're thinking, why? But maybe in the future, we will. In the near future, in the next couple of minutes, we can save the data somewhere and retrieve the data.
[00:06:57]
But if that happens, maybe we'll also trigger the observer pattern. So maybe I don't need to render the list initially. Maybe if the data changes, even if it's when the page loads, it will render the list anyway, okay, make sense? So well, renderList, what do I going to do?
[00:07:19]
So I'm going to first, I need to get all my lists. So my list of to-dos from the getInstance. Remember, I can also create a global variable for that pointer, it doesn't matter. I'm going to check, yeah, we have the classes.js, that's fine. And then I'm going to loop through, for every todo of that List.
[00:07:46]
Actually, not the list, but the items in the list. Do we have an items property? Do you remember? Let's get into the TodoList. Do we have an item for property? Yes, we do have a getter for a property, so it's a property. So we will loop through the items and we will do something.
[00:08:10]
So here comes the part where some of you may think it's a little dirty implementation, which is okay, because there are many ways to do that. I will mix some techniques at the same time here. I'm going to create a ListItem. This is actually the same code that was originally in the previous todo, okay?
[00:08:30]
So I'm creating an element, a DOM element of type Li, okay? Then I'm defining a class name. You can define the class name or you can add a class to the list, it's just the same to the item, or class name equals true. For this case, it's the same.
[00:08:52]
Then I'm going to define the innerHTML. And by the way, I'm not using text content, because I'm going to add some HTML here. There are some security concerns about using your HTML, but for now, it's fine. And I will just pull here the text from the current todo.
[00:09:12]
And also, I will render a button with the class='delete-btn'>Delete. I can also use an emoji or an image for that, it doesn't matter, okay? So that's my innerHTML, and then I'm going to do this. Let's see if you know what it is, dataset.text=todo.text. Does anyone know what dataset is?
[00:09:38]
This is the DOM API.
>> Speaker 3: See, data-attribute.
>> Maximiliano Firtman: Exactly, it's a collection of attributes that you can manage on every HTML element that from an HTML point of view, it's data- something. So actually, this is the Li. So from an HTML point of view, this is creating an Li with a data-text property with some content inside, okay?
[00:10:09]
You will see why we need that. And then now that I have the Li, I will talk to my, remember, we have the DOM pointing to this variable, we do have here the TodoList. This is the UL, we're going to append,
>> Maximiliano Firtman: Child that ListItem, okay, something like that.
[00:10:35]
>> Maximiliano Firtman: Are there better ways to do that? Yes, a lot. And in the next lab, we will see other options, okay, so that's why I don't wanna show you all on one particular lab. So let's see what happens. I will refresh, I will todo, let's go lunch, Add, wallah.
[00:10:55]
We have lunch there. If I try to have lunch again, let's see, nothing happens. I mean, I could have a message here or something, but yeah. Dinner, it works, but, oops, oops, oops. What's going on? Every time I'm rendering the change, I'm rendering the list, it's attaching to the previous rendering.
[00:11:20]
So okay, does it make sense? So we have that problem. So every time we are rendering the list, I should start talking to my TodoList and just clearing the whole list. A little dirty, but it works, okay? Makes sense? So now let me refresh. I can add a lunch, dinner, and it works.
[00:11:45]
I'm not seeing that repetition. When I will delete, nothing happens because I'm still missing that part. Let's add that code, and with that, we're going to be exactly with the same behavior as before, but with a lot of design patterns. So here, if we are in the Delete button, what we need is first, remember the value that we set here in dataset?
[00:12:16]
I'm going to use that to retrieve the todo that we need to delete. So the todo that we need to delete is going to be the event.target that's actually the,
>> Maximiliano Firtman: So let's understand what we are doing here. Let me show you here. Let's inspect, I want you to follow me.
[00:12:40]
So we have a lot Li, and then we have text within the layer text. This is a text node, a no text, and a button, okay? When you click on the button, I'm actually listening for the click event on the whole Li, but checking if it's the button.
[00:12:57]
So I wanna take the data-text, lunch, okay? So I'm inside the button now. The target is the button, so I need to go one level up to the Li to get the data-text. Does it make sense? I wanna take the lunch. So that's why here, I will take the target is the button.
[00:13:16]
I need to get to the parent node, that's the Li. And here, I will take from the set of data, the text. Then I will create the command,
>> Maximiliano Firtman: Command that the command will be of type delete and the arguments it's an array with that text, and we will execute that command, okay.
[00:13:44]
Makes sense?
>> Maximiliano Firtman: So if I refresh, let's see, lunch, Delete, it disappears. Lunch, I can add another one, and it works. So at this point, we have exactly the same behavior as before, but with a lot of more code, right?
Learn Straight from the Experts Who Shape the Modern Web
- In-depth Courses
- Industry Leading Experts
- Learning Paths
- Live Interactive Workshops