Source: http://vue-newsletter.com/vue-newsletter.png
In this opportunity, I invite you and explore my recent app as Single Page Application (SPA). But, before going any further, I will explain more detail how a component can be the most powerful in which client-side development of your app using VueJS. All of you have not deeply understand what is component related to VueJS's perspective, let you see at its official API and Guide. But, special for you don't waste more time, the most welcome to my article.
Murez Nasution
Attention!
All of experiments in this article has been tested and run well on the Windows platform. Other platforms never already tested, and some functionality would not run properly. Thank you.
For this moment, to be more easily understood, as always, I will use the method that would be the most effective, i.e. PnS – problem & solution.
Root Cause
Let's say that there is a simple note application template that consists of three main divisions, which are:
- Register, located at the most top of the document. It consists of two text inputs and a submit button, while pressed, creates a new note to be added down to Articles.
- Navigation, located on the left side of the document. Only contains labels that will display some information when selected. Next, it will be added some navigation buttons to update current selected article, as well as other additional needs
- Articles, located on the main part of the document. Contains all notes the user has created, which each note just consists of title and content.
As seen below,
In the early steps, how do I make a note n times, as in the Articles division above? Maybe, you will finish it in a way that is not much different as I have done the following,
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<div id="main"></div>
<script>
let init = function(n) {
let canvas = window.main;
for(let i = 0; i < n; i++) {
canvas.insertAdjacentHTML(
"beforeend",
"<div>"
+ "<h2>Title " + (i + 1) + "</h2>"
+ "<p>Lorem ipsum dolor sit amet.</p>"
+ "</div>"
);
}
}
init(4);
</script>
</body>
</html>
Save as index.html
in any directory on your PC, and the result looks like the following,
The way above looks still effective if the context is still simple that will only display the title and content in each note. The real problem is how in each note it consists of more complex components (for example, there are additional images or list), structures that differ from other notes or update the content on current selected note. It takes a relatively longer time to create a good codes and memory management. Then, what's one of the best solutions? At this moment, VueJS will help us and save a lot of works.
Solution
It's time! But, before you can use VueJS, you must do some ceremonies first, as following:
Requirements
- Install NodeJS
- Install
vue-cli
- Create New Project
- Rock ‘n Roll
For you who are familiar and have used Vue JS, can go directly to step (4)
. Make sure your PC is connected to the internet until the new project creation process is done.
1. Install NodeJS
You have to download NodeJS. Sure, we will not write any NodeJS codes, but just really need Node Package Manager (npm
).
2. Install vue-cli
Open Command Prompt, then write npm install -g vue-cli
. Wait for a moment.
3. Create New Project
Then, after vue-cli
installation was completed, move to any directory as your target. Write vue init <template-name> <project-name>
, commonly used:
vue init webpack my-project
Completely, you can find more current available templates in vuejs/vue-cli.
4. Install Text Editor
The following options deserve your attention:
- Visual Studio Code (cross-platform, free).
- Atom (cross-platform, free).
- Sublime Text (cross-platform, shareware).
- Notepad++ (Windows, free).
5. Rock ‘n Roll
Here are some steps that will be done to be able implementing note application template that has been designed from the beginning as seen in the most top picture.
5.1. Articles Creation
Create a file as SimpleArticle.vue
in the /src/components
relative directory and type the following code,
<template>
<div>
<h1>{{ title }}</h1>
<p>{{ content }}</p>
</div>
</template>
<script>
export default {
props: [ 'title', 'content' ]
}
</script>
Then, create another new file as Main.vue
in the same relative directory as the previous file and write down the following code,
<template>
<div>
<simple-article title='Title 1'
content='Lorem ipsum dolor sit amet.'>
</simple-article>
<simple-article title='Title 2'
content='Lorem ipsum dolor sit amet.'>
</simple-article>
</div>
</template>
<script>
import SimpleArticle from '@/components/SimpleArticle'
export default {
components: { SimpleArticle }
}
</script>
<style>
</style>
Make a minor change in /src/router/index.js
, which finally looks like the following,
import Vue from 'vue'
import Router from 'vue-router'
import Main from '@/components/Main'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: 'Home',
component: Main
}
]
})
Save the changes and we'll see the results soon. But, make sure to do the following three steps:
- Open Command Prompt, then go to the project folder that already made before,
- Type
npm run dev
, pressEnter
. Wait for a moment, and - Open browser, then access to
localhost:8080/
, it will look like the following,
Do you notice what's going on? In the previous scenario, it is seen that,
for(let i = 0; i < n; i++) {
canvas.insertAdjacentHTML(
"beforeend",
"<div>"
+ "<h2>Title " + (i + 1) + "</h2>"
+ "<p>Lorem ipsum dolor sit amet.</p>"
+ "</div>"
);
}
will iterate as much as n times and the result will be the same as,
<body>
<div id="main">
<div>
<h2>Title 1</h2>
<p>Lorem ipsum dolor sit amet.</p>
</div>
<div>
<h2>Title 2</h2>
<p>Lorem ipsum dolor sit amet.</p>
</div>
...
</div>
</body>
And Main.vue
also transforms html tags almost similar like the following,
<div id="app">
<div>
<simple-article title='Title 1'
content='Lorem ipsum dolor sit amet.'>
</simple-article>
<simple-article title='Title 2'
content='Lorem ipsum dolor sit amet.'>
</simple-article>
</div>
</div>
Then, for each <simple-article>
tag will be replaced in accordance with the existing template in SimpleArticle.vue
, then become as follows,
<div id="app">
<div>
<div>
<h2>Title 1</h2>
<p>Lorem ipsum dolor sit amet.</p>
</div>
<div>
<h2>Title 2</h2>
<p>Lorem ipsum dolor sit amet.</p>
</div>
</div>
</div>
So, if we add another new <simple-article>
tag, then a new note will appear, and so on. The most important thing here is the way a parent (template that uses and declares the <simple-article>
tag) sends data to its child (the SimpleArticle.vue
component), i.e. through attributes.
We see that a child needs defined data in props, in this context is props: [ 'title', 'content' ]
.
Attention!
The value defined in the props should not be replaced, this is because the context of the data owned by the parent and only it has been responsible what happens to the props. Thus, a child should not interfere with the value in props (read-only). The app will still run well while still attempting to violate this rule. However, we will get a warning from VueJS to promptly correct this error in the Console. Instead, use thedata
properties to define variables in the local context (child itself).
Then parent provides and sends the data through the attribute of the <simple-article>
tag, so simple that <simple-article title = '...' content = '...'>
. Then, child can insert the data that has been sent in the html tag using the {{ ... }}
syntax (next just known as interpolation), so <h1> {{ title }} </ h1>
will display the text in the title property sent by its parent. And here's the component principle in VueJS perspective.
Looks the same and ordinary? OK. Let's go a step further. We will make Articles become more dynamic, by representing them as array. Next, add the following code to Main.vue
,
<script>
import SimpleArticle from '@/components/SimpleArticle'
export default {
data: function() {
return {
articles: [
{ title: 'Title 1', content: 'Lorem ipsum dolor sit amet.' },
{ title: 'Title 2', content: 'Lorem ipsum dolor sit amet.' }
]
}
},
components: { SimpleArticle }
}
</script>
And just a bit modification on attribute in tag <simple-article>
, so be
<simple-article v-for="article of articles"
v-bind:title="article.title"
v-bind:content="article.content">
</simple-article>
As same as previous one, but here we get some advantages, i.e.:
- The
v-bind: <any-prop>
attribute is useful for making any property dynamic (next known as reactive), so that the values in the property can be changed fit to condition. This attribute must be populated with variables (also by using JavaScript expressions) declared in thedata: function () {return { ... }}
.
Attention!
The value in the data property must be a function that always gives new objects. Why should it be so? Wait for my next new article :-).
- The v-for attribute is useful for doubling the tag associated with this attribute n times. In this context the
<simple-article>
tag will be created as many elements as in the data articles. The value inv-for
can be the same JavaScript expression to iterate on the object.
5.2. Register Creation
Previously, we have finished implementing articles, then we will design register division. Go back to the Main.vue
file, then add two inputs to receive the title and content, a submit button, as well as the method to be executed when the button is clicked. So the Main
component becomes as follows,
<template>
<div>
<input type='text' placeholder='Title' v-model='title' />
<textarea placeholder='Content' v-model='content'></textarea>
<button v-on:click='submit'>Submit</button>
<simple-article v-for="article of articles"
v-bind:title="article.title"
v-bind:content="article.content">
</simple-article>
</div>
</template>
<script>
import SimpleArticle from '@/components/SimpleArticle'
export default {
data: function() {
return {
title: ‘’,
content: ‘’,
articles: [ ]
}
},
methods: {
submit: function() {
if(Boolean(this.title) && Boolean(this.content)) {
this.articles.unshift({ title: this.title, content: this.content })
this.title = ''
this.content = ''
}
}
},
components: { SimpleArticle }
}
</script>
Here, let the article blank. Next, focus to the browser and the results will be updated immediately (if no changes, press F5 or refresh button). For a while, the part that already exists in the document is only register divisions. Fill in the title and content, then hit submit. Thus, new notes will appear in the articles division, as shown below,
Cool! At this point, we have noticed the new attributes, i.e. v-model
and v-on:<any-event>
. We will discuss it more in depth in separate articles. For now, we just need to know that the v-on: click
attribute will trigger the calling of the submit method when the button is pressed. All required methods on the component must be declared in properties methods. And in every method, it needs this
that references to local variables.
5.3. Navigation Creation
This division is required to display an information when a note is selected. In this example, we will only show the date of the note when it was first created. The trigger is the click event on the title of the note. Already thought about how to do? OK. Let's get started!
In the Main.vue
file, add more variable, e.g. created
which will save the date of the note when it was first created. Then, we need an additional tag to display it. Remember! The trigger is the click event, on the title of the note. So, we also have to add a method, call it selected
on the SimpleArticle
component.
So, the addition to be done, among others, is on <template>
in Main.vue
,
<p> {{ created }} </ p>
Then, the addition to <script>
,
data: function() {
return {
title: '',
content: '',
created: '',
articles: [ ]
}
}
Do not forget to add new attribute to existed object to be saved to Articles,
this.articles.unshift({ title: this.title, content: this.content, created: Date.now() })
And finally in the SimpleArticle.vue
file, add the selected
method and,
<h1 v-on:click='selected'>{{ title }}</h1>
Attention!
We have agreed not to change the value of props. Then, what should be we do in theselected
method? How does child (SimpleArticle
component) provide data back to its parent? The solution isevent
. So we need a method that will trigger an action in the parent context, it is$emit(eventname, value)
. For more details, the code in theSimpleArticle.vue
file will be,
<template>
<div>
<h1 v-on:click='selected'>{{ title }}</h1>
<pre>{{ content }}</pre>
</div>
</template>
<script>
export default {
props: [ 'title', 'content', 'created' ],
methods: {
selected() {
this.$emit('selected:article', this.created)
}
}
}
</script>
<style scoped>
h1 { cursor: pointer }
</style>
And finally the Main.vue
file will be as follows,
<template>
<div>
<p>{{ created }}</p>
<input type='text' placeholder='Title' v-model='title' />
<textarea placeholder='Content' v-model='content'></textarea>
<button v-on:click='submit'>Submit</button>
<simple-article v-for="article of articles"
v-bind:key='article.created'
v-bind:title='article.title'
v-bind:content='article.content'
v-bind:created='article.created'
v-on:selected:article='selected'>
</simple-article>
</div>
</template>
<script>
import SimpleArticle from '@/components/SimpleArticle'
export default {
data: function() {
return {
title: '',
content: '',
created: '',
articles: [ ]
}
},
methods: {
submit: function() {
if(Boolean(this.title) && Boolean(this.content)) {
this.articles.unshift({ title: this.title, content: this.content, created: Date.now() })
this.title = ''
this.content = ''
}
},
selected: function(v) {
let d = new Date()
d.setTime(v)
this.created = 'Created Date: ' + (d.getMonth() + 1) + '-' + d.getDate() + '-' + d.getFullYear()
+ ' ' + d.getHours() + ':' + d.getMinutes() + ':' + d.getSeconds()
}
},
components: { SimpleArticle }
}
</script>
The result will look like the following,
And finally, by applying some styles, our app will looks like this,
Conclusion
- The way a parent to be able sending data to a child is through an attribute.
- Child can receive data sent by its parent through props.
- Components can only read props, while those who responsible to what is completely happening with props are just parent.
- The scope of the child over its own data (local variables) is through the
data
property. - Property of
data
should always provide new objects in each instance. Then thedata
must be a function. - By giving the
v-bind:
prefix in an attribute, then the value of this attribute must be a variable or the JavaScript expression and props will be reactive. Which means that changing the value in parent, will also change the value in its child. - To do two-way interaction between parent and child (without having to change props) is with
$emit(eventname, value)
. - VueJS is all about Reusable component.
Posted on Utopian.io - Rewarding Open Source Contributors
Your contribution cannot be approved yet because.
1 - Give proper Picture Courtesy for all the images used.
2 - You should not ask for follow, remove the line "Hopefully useful, and follow up my next article by click Follow here."
See the Utopian Rules. Please edit your contribution to reapply for approval.
You may edit your post here, as shown below:

You can contact us on Discord.
[utopian-moderator]
I've finished my editing related to your instructions. Thank you.
Thank you for the contribution. It has been approved.
You can contact us on Discord.
[utopian-moderator]
Thank you.
Hey @murez-nst I am @utopian-io. I have just upvoted you!
Achievements
Community-Driven Witness!
I am the first and only Steem Community-Driven Witness. Participate on Discord. Lets GROW TOGETHER!
Up-vote this comment to grow my power and help Open Source contributions like this one. Want to chat? Join me on Discord https://discord.gg/Pc8HG9x