Check out a free preview of the full Vanilla JS: You Might Not Need a Framework course

The "Rendering the Menu" Lesson is part of the full, Vanilla JS: You Might Not Need a Framework course featured in this preview video. Here's what you'd learn in this lesson:

Maximiliano walks through creating an event listener that listens for and renders changes to the coffee master's menu. A student's question regarding if the shadow DOM allows the use of local IDs is also covered in this segment.

Preview
Close

Transcript from the "Rendering the Menu" Lesson

[00:00:00]
>> So we have the proxy, and that proxy is broadcasting changes. So now let's go back a little bit to our app.js file. And here, we were loading data. Remember, load data was actually going to the API and storing the menu. And here, we don't see that as a consumer, but it seems like we are using the proxy.

[00:00:28]
When we change the menu, that proxy should be broadcasting that there is a change. Well, because of that, now we can go to, for example, our Menu.Page.js, and somewhere, for example, in our connected callback, we can listen for that event for appmenuchange. So when the menu changes, I will call, for example, a render method that we need to create just to not do everything in that event handler.

[00:01:05]
Make sense? So that means that we can have a render method because the data has changed, the menu is available. We can start rendering our user interface. And here, we are going to use a mix of techniques, as I mentioned before. And for the techniques that are just the same or just like writing a lot of code, we will probably switch to pasting the code that we know it's working.

[00:01:35]
The first time, I will type it completely to explain what I'm doing, and then the second one, that is the same, there is no need for that. So, first, someone can be setting the menu as null. So I should check if there is a menu or not. And if there is not a menu, maybe what I want is to render a paragraph or an image, something saying loading, okay?

[00:02:03]
So, in this case, I can take my root, what is the root? The root is the shadow DOM, and search for an ID menu. I can use querySelector or get element by ID, and change its inner HTML as, for example, loading. This is one way, use innerHTML is a way to change the content of something.

[00:02:31]
So if the menu is null, then it will say loading. If it's not null, I will write a lot of stuff here. For example, first, let's analyze the structure because we haven't seen that structure before. The menu.json looks like this, it has, first, an array of categories, like hot coffee, ice coffee, okay?

[00:02:58]
And each category has a name and an array of products. So we need to loop through this. So we're going to start with categories first. We can use for each or for (let category of app.store.menu). And now, I can use innerHTML, so I can create a long string, I can concatenate the string and then set the innerHTML to the menu.

[00:03:26]
Or just to do things in different ways, we can just create an li for the category, and say document.createElement("li"). And then for the li category, we are going to create an h3 for the name of the category and a list for products, okay? So I can do it with createElement, so I can create an h3.

[00:03:59]
Or in this case, because I think it's pretty simple to understand, I'm going to use innerHTML. So I'm going to say that we will have an h3 and then a list of products that will have a class category. And that's all I need here. And finally, I will take the menu and I will append that liCategory at the end of it.

[00:04:32]
So for each category, I'm creating a list item and an li, and inside the li, I have, one, an h3 and a list of products. I'm mixing techniques here, okay? Remember that. For h3, I wanna put inside the name of the category, I already have the name of the category in category.name.

[00:04:54]
So I can use the template here, category.name, dollar sign, curly braces, expression. Category.name is the name of the current category. Make sense? So now, coming back to the project, I'm seeing this, which it's better than the violet title that we had before, right? So, it worked. We are injecting the DOM dynamically.

[00:05:30]
And if I inspect this, I have a menu with four li's, each li with an h3 and an empty ul. Make sense? Do you have any question on this, that code? So we are creating dynamically HTML based on the menu. And by the way, we didn't realize that actually our proxy worked.

[00:06:00]
This happened because the event appmenuchange was fired, and that triggered our render method and it worked. And if someone is changing that menu with a new version of the menu, it will trigger, again, render, Okay? Something that is not completely okay here is that we are not clearing the menu.

[00:06:28]
Remember I mentioned when you're doing vanilla JS, this is important. When you're using appendChild before the for, we should clear the contents, why? Because if not, for example, we will still keep the original loading, because we will keep the previous content and we are appending new elements. Well, you can clear this up before doing that.

[00:06:53]
And by the way, you can cache the menu if you want instead of accessing querySelector every time. So now, what about the products? Because now I need to define the product, each product inside here, okay? Well, instead of, I'm talking about the li's that goes here. What I want for each item, for each row, I wanna create another component, okay?

[00:07:26]
So we are going to create another component similar to what you do in React or in Angular, you create the component for each item, you have one for the list, and one for each component. I'm going to create a new component, okay? But, before actually creating the component, let's try to understand how I'm going to do that.

[00:07:46]
So for example, after we do that appendChild, I'm going to take the current category, and for each products, I'm going to, for example, do a map or a forEach, I'm sure you can use a for each. And you can say for each product, I'm going to do something, what?

[00:08:11]
Well, I'm going to create a new element, okay? So I'm going to create an item element, how? document.createElement. Of which type? A type that I'm going to create. Let's call that product-item. It doesn't exist yet, okay? Will it work? It will create that HTML tag, but the browser will not know how to render that, so it will render nothing, okay, so far.

[00:08:39]
So now what I need is to pass the current product to that component so it can render the content, okay? So, for that, I'm going to use dataset.product. And because it's an object, I need to pass it as a string. This is not the only way to do that, okay?

[00:08:58]
But, again, I'm using different techniques. So I can stringfy, I can pass an ID also, instead of the whole product, anyway. I try to show you different techniques. And then I need to attach this to the, where I need to put this? Here, in this ul, okay? Makes sense?

[00:09:20]
That ul is in file liCategory. So I can ask to the liCategory to find, by a selector, the ul, and then append the child item, something like that. This is still not going to work, because we haven't registered that custom element yet. But the idea, I think the idea should work.

[00:09:51]
So if I see this here, if I inspect this, I see a ul with a lot of product items, each one with the data product inside rendering nothing yet, okay? But it's okay. So the next step is to create the custom element and register that element. Do you have any questions at this point?

[00:10:16]
Does it make sense so far? Yeah.
>> Does the shadow DOM allow you to use local IDs? For example, is it valid to have to shadow elements side by side with the same ID?
>> Yes, because it's its own documents, so a shadow DOM has its own document with its own rules.

[00:10:35]
But so far, we don't have a shadow DOM on that one. And I don't think I want shadow DOM for the product item, just to show you that you don't need to use a shadow DOM every time. So we will use shadow DOM for each page component. But then, I wanna share the CSS stylesheet, for example, for all the other web components within that page.

[00:11:02]
It's our decision, okay? So don't think that shadow DOM goes always.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now