Improving the code structure
Create Vue.js single file components and learn about slots, props, and custom events.
Get the project source code below, and follow along with the lesson material.
Download Project Source CodeTo set up the project on your local machine, please follow the directions provided in the README.md
file. If you run into any issues with running the project source code, then feel free to reach out to the author in the course's Discord channel.
Lesson Transcript
[00:00 - 00:11] Before we move on to adding more features, you might have noticed that this file is getting bigger and bigger. If your app is only small, keeping all the code in one component might work.
[00:12 - 00:22] But the more features you're going to add, the harder it is going to be to maintain code like this. This is why we want to split the code up into components.
[00:23 - 00:34] If you create a component that you can reuse, you will have to repeat less code and it will be easier to maintain. Additionally, it will make the code more readable.
[00:35 - 00:50] The first component we will create will be called "Resume section". We navigate in the component folder and create a file with the name "Resume section".
[00:51 - 01:03] This component serves purely as a layered component and does not add functionality. It will only need a template section and a style section, now script necessary.
[01:04 - 01:19] The goal is to render the resume content just like we did before, but instead of wrapping content in diff class resume section directly, we want to wrap it in the resume section component. Therefore, we need a way to pass content into a component.
[01:20 - 01:27] For this, view provides the slot tag. The slot makes sense once you see how it is used.
[01:28 - 01:42] Anything between the opening and the closing tags of the component will be displayed instead of the slot tags. It allows us to split up content in a way that makes components more reusable.
[01:43 - 01:50] I can pass in anything I want, a headline, a button, etc. And the resume section component does not need to know.
[01:51 - 02:26] [silence] But before we can use our component, we have to import it within the script tag . In our app component, we import the resume section component and register it in the components object.
[02:27 - 02:41] The view documentation explains that this is necessary to make our component available as a tag within the template. Now that we have registered our component, we can use the tag in the template.
[02:42 - 03:45] I am going to wrap everything that was wrapped in diff resume section into the resume section component. [silence] [silence] [silence] As you can see, it gets rendered just like before, which means that view passes the inner content of the component into the slot.
[03:46 - 03:59] The section headlines are another part of the app template that would do well as a component. It is always the same markup in styling, and we want to reduce the amount of markup in styling in our app component.
[04:00 - 04:18] By creating a component for it, we can isolate the markup in styling for the headline and reuse the same component instead of repeating the code. We want our component to be called section headline, so we create a file called sectionheadline.view.
[04:19 - 04:44] [silence] First, we copy over the markup from app.view that we want this component to display. The index and the headline array is different for every headline. The zero can of course not stay there.
[04:45 - 04:57] Our component also does not know about the headline's array. This data lives in the app component. We have to pass this information to the section headline component to display it from there.
[04:58 - 05:32] [silence] For this, we have props in view. Props are like variables that you pass down from the parent to the child component. These variables contain a value. We are going to be using sectionheadline in our app component, which makes up the parent component and sectionheadline the child component.
[05:33 - 05:53] In the app component, we have to import sectionheadline and register it in the components object. [silence] Now we can use it in the template. To pass down a prop, you add an attribute with the name of the prop.
[05:54 - 06:11] You will be able to access the value of the attribute, for example test headline, in the child component. To use the prop and the sectionheadline component, we have to state which props we expect explicitly.
[06:12 - 06:30] You can do this with an array containing the prop names as a string. [silence] If you don't have view which props you are expecting, the prop won't be available in your component.
[06:31 - 06:40] You can read more about explicit prop declaration in the view documentation. Now you can see that the headline is displayed correctly.
[06:41 - 06:56] [silence] The child component does not need to know the entire headline's array. For displaying the headline, it only needs the headline at a specific index.
[06:57 - 07:19] For this, we can use the vbind directive again, which allows us to reference data from the data object as the attribute value. The JavaScript expression will be evaluated and then a value, so in our case the headline that exists at index 0 of the headline's array, will be passed along as a prop.
[07:20 - 07:38] We are displaying the headline, but we are not saving the result of the headline editing anymore. Because the app holds all the data for the resume, we need to inform the app component about changes in the headline text, in case the user edits it.
[07:39 - 07:46] We do this by emitting a custom event. We call the event handler notify_parent.
[07:47 - 08:03] For that, we add a method where we emit a custom event called headline editor. To emit custom events, view provides the emit's function, which you can call with this dot $ emits with a new method.
[08:04 - 08:20] Along with the event name, we can pass a value that the listener will receive. The app component needs to know the new value of the headline. The new value can be accessed with inner text of the node that triggered the event.
[08:21 - 08:38] Therefore, we pass this information along. In the parent component, app.view, we listen to the headline edited event by adding the vund directive with the event name in kverb case.
[08:39 - 08:53] When emitting the event in view, developers commonly use kammercase. You can listen to the event either using kammercase or with kverbcase.
[08:54 - 09:06] View recommends using kverbcase event listeners in the template, so we will use that. What does not work is emitting a kammercase event and then listening to it in lowercase.
[09:07 - 09:14] HTML is case insensitive, but view is not, so it is best to stick to the convention here. The same applies to props.
[09:15 - 09:30] Our prop headline is only lowercase and we reference it as such in the template . However, if we had a prop such as headline text, the convention is to use kam mercase in the script section and reference it as kverbcase in the template.
[09:31 - 09:39] Same for events. We need an event handler that passes the data from the event and the current index.
[09:40 - 09:51] If we only needed to pass on the data that the custom event sends, we would not have to pass arguments to the event handler explicitly. The data from the event is passed automatically.
[09:52 - 10:05] But since we also need to pass the current index, we do have to list our arguments. To reference the data we receive from an event, we use the dotter sign event argument.
[10:06 - 10:28] We can change our existing update headline method to accept the parameter's new value as well as the index. The new value already contains event.target.intertext.
[10:29 - 10:49] Next, we will move the styling associated with the section headline over from the app component to the section headline component. For that, we will add a scope style section to the section headline component.
[10:50 - 10:57] Finally, we can replace all the section headlines with a new component. Make sure to adjust the indexes accordingly.
[10:58 - 11:33] To add a new component, we will add a new component. Pause here and check with the view DevTools extension in your browser if the headline values still update properly when you edit them.
[11:34 - 11:43] Next up for becoming an independent component is our contact section. We only use it once, but a component's purpose is not only for reusing.
[11:44 - 11:56] Components are also useful for isolating the markup, styling and logic, which helps maintainability. Since the contact section is fairly big markup-wise, I want to isolate this in a separate component.
[11:57 - 12:29] Let's create a component with the name contact and move the entire URL node and its content in there. To render the contact data property, we need to pass it down and add a new component.
[12:30 - 12:49] To render the contact data property, we need to pass it down as a prop. We therefore register a property with the name contact.
[12:50 - 13:31] In the parent component, we import the contact component and pass the contact property as the value for the contact prop. We will inform the parent component with a custom event, named "edit".
[13:32 - 13:41] We don't have to define a new method for handling this event. We can use the update nested property method, which we defined earlier.
[13:42 - 14:05] This previously defined method takes the event in two key arguments. In our case, we will need to pass "contact for key1" and "phone email address for key2" depending on the node.
[14:06 - 14:24] In our event handler within the contact component, we pass the event name as the first argument to the emit method, and the arguments the event handler in the parent expects after. In the case of the first node, this would be "dollar sign emit", and then event name "edit".
[14:25 - 14:38] We pass the event with "dollar sign event", and then "contact for key1" and " phone for key2". Let's test this out.
[14:39 - 14:57] As you can see, the contact data is still displayed properly, and editing it still updates the data property correctly. As an optional last step, you can add icons in front of phone, email, and address.
[14:58 - 15:05] Here's how this would look. If you want to give it a go, pause the video here and try adding them yourself.
[15:06 - 15:16] I used font awesome free icons for this by copying their SVG from the font awesome website. Now that you have tried it out yourself, let's look at my solution.
[15:17 - 15:39] One thing to watch out for is that you're going to have to move the content editable attribute, as well as the event listener to a separate node. If you have the icon, as well as the text together in the node, in the "li" node, the editing could also remove the icon, which we don't want.
[15:40 - 16:22] We only want the user to be able to edit the text. [ Silence ] [ Silence ] I'm also adding some styling here.
[16:23 - 17:02] As you can see, without styling, it looks a bit off. [ Silence ] Awesome!
[17:03 - 17:14] We have created several components and reduced the code in our app component. We have learned about slots, props, and custom events.
This lesson preview is part of the Interactive Vue.js Resume Builder course and can be unlocked immediately with a \newline Pro subscription or a single-time purchase. Already have access to this course? Log in here.
Get unlimited access to Interactive Vue.js Resume Builder, plus 70+ \newline books, guides and courses with the \newline Pro subscription.