Summary of Vue JS2 Tutorial by Net Ninja (Part 3 of 3)

JL’s Self-teaching Story #4

Lim
Lim
Sep 3, 2018 · 18 min read

[JL’s Self-teaching Story] Series

[Net Ninja] JS Regular Expressions
[Net Ninja] Vue JS2 (Part1, Part2, Part3(current))
[Net Ninja] Vuex
[Net Ninja] Python3 (Part1, Part2, Part3)
[Net Ninja] Django (Part1, Part2, Part3)
[Net Ninja] Sass (Part1, Part2)
[Sean Larkin] Webpack4 (Part1)

🌲 This is the last part of my summary of Vue JS Tutorial by Net Ninja on YouTube.


31) HTTP Requests
32) GET Requests
33) Custom Directives
34) Filters
35) Custom Search Filter
36) Registering Things Locally
37) Mixins
38) Setting Up Routing
39) Routing : Hash vs History
40) Adding Router Links
41) Route Parameters
42) Posting to Firebase
43) Retrieving Posts from Firebase

If you haven’t set up a development server for Vue, please refer to “16) The Vue CLI” chapter in the previous post for details of running a development server by using Vue CLI3.

If you already did that, just type npm run dev in the terminal for Mac OS and the command line for Windows to run a development server.


31) HTTP Requests (YouTube)

In order to store data in a database, we need to makeHypertext Transfer Protocol (HTTP) requests.

  1. v-if='!submitted' is used to hide the form after “Add Blog” button is pressed.
  2. By using v-if='submitted', display “Thanks for adding your post!” message.
  3. title: '', content: '' allows us to display a title & a content that a user enters.
[index.html]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>vuejs-playist</title>
</head>
<body>
<div id="app"></div>
<script src="/dist/build.js"></script>
</body>
</html>
-----------------------------------
[src > main.js]
import Vue from 'vue'
import App from './App.vue'
import axios from 'axios'
Vue.prototype.$http = axios;new Vue({
el: '#app',
render: h => h(App)
});
-----------------------------------
[src > App.vue]
<template>
<div>
<add-blog></add-blog>
</div>
</template>

<script>
import addBlog from './components/addBlog.vue';
export default{
components{
'add-blog': addBlog
}
}
</script>
-----------------------------------
[src > components > addBlog.vue]
<template>
<div id='add-blog'>
<h2>Add a New Blog Post</h2>
<form v-if='!submitted'>
<label>Blog Title: </label>
<input type='text' v-model.lazy='blog.title' required />
<label>Blog Content: </label>
<textarea v-model.lazy='blog.content'></textarea>

<div id='checkboxes'>
<label>Ninjas</label>
<input type='checkbox' value='ninjas' v-model='blog.categories'/>
<label>Wizards</label>
<input type='checkbox' value='wizards' v-model='blog.categories'/>
<label>Mario</label>
<input type='checkbox' value='mario' v-model='blog.categories'/>
<label>Cheese</label>
<input type='checkbox' value='cheese' v-model='blog.categories'/>
</div>

<label>Author: </label>
<select v-model='blog.author'>
<option v-for='author in authors' :key='author.id'>{{ author }}</option>
</select>
<button @click.prevent='post'>Add Blog</button>
</form>
<div v-if='submitted'>
<h3>Thanks for adding your post</h3>
</div>
<div id='preview'>
<p>Blog Title: {{ blog.title }}</p>
<p>Blog Content: </p>
<p>{{ blog.content }}</p>
<p>Blog Categories</p>
<ul>
<li v-for='category in blog.categories' :key='category.id'>{{ category }}</li>
</ul>
<p>Author: {{ blog.author }}</p>
</div>
</div>
</template>

<script>
export default{
data(){
return{
blog:{
title: '',
content: '',

categories: [],
author: ''
},
authors: ['The Net Ninja', 'The Angular Avenger', 'The Vue Vindicator'],
submitted: false
}
},
methods:{
post: function() {
const axios = require('axios');
axios.post('https://jsonplaceholder.typicode.com/posts', {
title: this.blog.title,
body: this.blog.content,
userID: 1
}).then(response => {
console.log(response);
this.submitted = true;
});
}
}
}
</script>

In 2.2.0+, when using v-for with a component, a key is now required (Official Website).

If the key is not included, the following error message shows up:

[eslint-plugin-vue] [vue/require-v-for-key] Elements in iteration expect to have 'v-bind:key' directives.

Available to see the full code with syntax highlighting on GitHubGist.

  • Net Ninja used “JSON: Placeholder”, fake online REST API for testing and prototyping.

A RESTful API is an Application Program Interface (API) that uses HTTP requests to GET, PUT, POST and DELETE data. A RESTful API — also referred to as a RESTful web service — is based on REpresentational State Transfer (REST) technology, an architectural style and approach to communications often used in web services development. (Margaret Rouse)


On Nov 3, 2016, Even You, creator of Vue.js, wrote an article called “Retiring vue-resource”. The article says, “As Vue users, many of you may have used vue-resource for handling ajax requests in your Vue applications. For a long time it’s been thought of as the “official” ajax library for Vue, but today we are retiring it from official recommendation status” (blog).

So, I decided to use axios instead of vue-resource. Axios is “Promise based HTTP client for the browser and node.js” (GitHub)

Since Net Ninja used vue-resource in his VueJS2 tutorial, I made a few adjustments.

  1. Use import axios from ‘axios’ instead of import VueResource from 'vue-resource’ in main.js file.
  2. Enter Vue.prototype.$http = axios instead of Vue.use(VueResource).
  3. Inside of post: function(), include const axios = require(‘axios').
  4. Type axios.post instead of this.$http.post.
  5. response instead of data in the then() method : will explain the reason in the next chapter.
  6. Use => instead of function().

The then() method returns a Promise.(MDN)


32) GET Requests (YouTube)

We use GET requests to retrieve data. An example of sample objects in “JSON: Placeholder” is the following:

{
"userId": 1,
"id": 1,
"title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
"body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"
}
[src > app.vue]
<template>
<div>
<show-blogs></show-blogs>
</div>
</template>

<script>
import showBlogs from './components/showBlogs.vue';

export default{
components{
'show-blogs': showBlogs
}
}
</script>
-----------------------------------
[src > components > showBlogs.vue]
<template>
<div id='show-blogs'>
<h1>All Blog Articles</h1>
<div v-for='blog in blogs' class='single-blog'>
<h2>{{ blog.title }}</h2>
<article>{{ blog.body }}</article>
</div>
</div>
</template>

<script>
export default{
data(){
blogs: []
},
created(){
const axios = require('axios');

axios.get('https://jsonplaceholder.typicode.com/posts')
.then(response => {
console.log(response);
this.blogs = response.data.slice(0,10);
});
}
}
</script>

<style scoped>
#show-blogs{
max-width: 800px;
margin: 0 auto;
}
.single-blog{
padding: 20px;
margin: 20px 0;
box-sizing: border-box;
background: #eee;
}
</style>

Available to see the full code with syntax highlighting on GitHubGist.

As I explained in the previous chapter, I made a few adjustments, because I used axios instead of vue-resource. The reason for the 5th difference(using response instead of data in the then() method) is the following:

[Net Ninja’s code]

.then(function(data) {
console.log(data);
this.blogs = data.body.slice(0,10);

[My code]

.then(response => {
console.log(response);
this.blogs = response.data.slice(0,10);

> In order to access sample objects provided by JSON Placeholder, I needed to use data instead of body. So, not to be confused with that, I passed down response instead of data.


33) Custom Directives (YouTube)

  • Created a custom directive called “v-rainbow”. It generates a random color for each title.
  • Created another custom directive called “v-theme” to provide options : narrow & wide.
  • Attached an argument called “column” to the v-theme custom directive to link a background option
[src > components > showBlogs.vue]
<template>
<div v-theme:column="'narrow'" id='show-blogs'>
<h1>All Blog Articles</h1>
<div v-for='blog in blogs' class='single-blog'>
<h2 v-rainbow>{{ blog.title }}</h2>
<article>{{ blog.body }}</article>
</div>
</div>
</template>

<script>
// same as above
</script>

<style scoped>
/* same as above */
</style>
-----------------------------------
[src > main.js]
// same as above
Vue.directive('rainbow', {
bind(el, binding, vnode){
el.style.color = '#' + Math.random().toString().slice(2,8);
}
});

Vue.directive('theme', {
bind(el, binding, vnode){
if(binding.value == 'wide'){
el.style.maxWidth = '1200px';
} else if(binding.value == 'narrow'){
el.style.maxWidth = '600px';
}

if(binding.arg == 'column'){
el.style.background = '#ddd';
el.style.padding = '20px';
}
}
});
new Vue({
// same as above
});

Available to see the full code with syntax highlighting on GitHubGist.

  1. In v-theme:column, used single quotation marks to wrap “narrow” inside a double quotation marks. Without the single quotation marks, the following error message appears in the console: Property or method “narrow” is not defined on the instance but referenced during render. “narrow” is not a property or method. It’s just a value. In order to specify that it’s a string, we need to wrap the word with single quotation marks.
  2. Added '#' before Math.random() function, because a hexadecimal color starts with “#” (e.g., #00fefe).
  3. “The Math.random() function returns a floating-point, pseudo-random number in the range 0–1 (inclusive of 0, but not 1) with approximately uniform distribution over that range — which you can then scale to your desired range” (MDN). The output of console.log(Math.random()) is 0.XXXXX… Therefore, the first number in slice() function is “2”.

34) Filters (YouTube)

Vue.js allows you to define filters that can be used to apply common text formatting (official website)”.

  • Made titles uppercase
  • Cut bodies down to show the maximum of 100 characters.
[src > components > showBlogs.vue]
<template>
<div id='show-blogs'>
<h1>All Blog Articles</h1>
<div v-for='blog in blogs' class='single-blog'>
<h2>{{ blog.title | to-uppercase }}</h2>
<article>{{ blog.body | snippet }}</article>
</div>
</div>
</template>
<script>
// same as above
</script>

<style scoped>
/* same as above */
</style>
-----------------------------------
[src > main.js]
import Vue from 'vue'
import App from './App.vue'
import axios from 'axios'

Vue.prototype.$http = axios;
Vue.filter('to-uppercase', function(value){
return value.toUpperCase()
});
Vue.filter('snippet', function(value){
return value.slice(0,100) + '...'
});

new Vue({
el: '#app',
render: h => h(App)
});

Available to see the full code with syntax highlighting on GitHubGist.

  1. | <name of a filter> in showBlogs.vue : appended to the end of a JavaScript expression, denoted by the “pipe” symbol.
  2. Vue.filter('<name of a filter>', function(){}) in main.js : define a filter globally before creating a Vue instance.

35) Custom Search Filter (YouTube)

When a user type word(s) on a search bar, only blogs with the word(s) remains on the screen.

[src > components > showBlogs.vue]
<template>
<div id='show-blogs'>
<h1>All Blog Articles</h1>
<div v-for='blog in filteredBlogs' class='single-blog'>
<h2>{{ blog.title | to-uppercase }}</h2>
<article>{{ blog.body | snippet }}</article>
</div>
</div>
</template>
<script>
export default{
data(){
blogs: [],
search: ''
},
created(){
// same as above
},
computed:{
filteredBlogs: function(){
return this.blogs.filter((blog) => {
return blog.title.match(this.search) || blog.body.match(this.search);
});
}
}
}
</script>

<style scoped>
/* same as above */
</style>

Available to see the full code with syntax highlighting on GitHubGist.

  • A || B means “A” or “B”. In this case, “filteredBlogs” filter searches all blog posts, check each blog post to see if the blog post contains word(s) typed in the search bar in its title or body, and returns only matched blog post(s) on the screen.

36) Registering Things Locally (YouTube)

In the previous chapters, we used “to-uppercase” & “snippet” filters registered globally.

[src > main.js]
Vue.filter('to-uppercase', function(value){
return value.toUpperCase()
});
Vue.filter('snippet', function(value){
return value.slice(0,100) + '...'
});

In this chapter, we’ll register the filters locally in showBlogs.vue. Also, we’ll add v-rainbow directive locally.

[src > components > showBlogs.vue]
<template>
<div id='show-blogs'>
<h1>All Blog Articles</h1>
<div v-for='blog in filteredBlogs' class='single-blog'>
<h2 v-rainbow>{{ blog.title | to-uppercase }}</h2>
<article>{{ blog.body | snippet }}</article>
</div>
</div>
</template>
<script>
export default{
data(){
blogs: [],
search: ''
},
created(){
// same as above
},
computed:{
// same as above
},
filters:{
'to-uppercase': function(value){
return value.toUpperCase();
},
snippet(value){
return value.slice(0,100) + '...';
}
},
directives:{
'rainbow':{
bind(el, binding, vnode){
el.style.color = '#' + Math.random().toString().slice(2,8);
}
}
}
}
</script>

<style scoped>
/* same as above */
</style>
-----------------------------------
[src > main.js]
import Vue from 'vue'
import App from './App.vue'
import axios from 'axios'

Vue.prototype.$http = axios;

new Vue({
el: '#app',
render: h => h(App)
});

Available to see the full code with syntax highlighting on GitHubGist.

> 'to-uppercase': function(value) can be written as toUppercase(value).


37) Mixins (YouTube)

Mixins are a flexible way to distribute reusable functionalities for Vue components. A mixin object can contain any component options. When a component uses a mixin, all options in the mixin will be “mixed” into the component’s own options (official website)”.

[src > App.vue]
<template>
<div>
<show-blogs></show-blogs>
<list-blogs></list-blogs>
</div>
</template>

<script>
import showBlogs from './components/showBlogs.vue';
import listBlogs from './components/listBlogs.vue';

export default{
components{
'show-blogs': showBlogs,
'list-blogs': listBlogs
}
}
</script>
-----------------------------------
[src > components > showBlogs.vue]
<template>
<!-- same as above -->
</template>
<script>
import searchMixin from '../mixins/searchMixin';
export default{
data(){
blogs: [],
search: ''
},
created(){
// same as above
},
filters:{
// same as above
},
directives:{
// same as above
}
}
</script>

<style scoped>
/* same as above */
</style>
-----------------------------------
[src > components > listBlogs.vue]
<template>
<!-- same as above -->
</template>
<script>
import searchMixin from '../mixins/searchMixin';
export default{
data(){
blogs: [],
search: ''
},
created(){
// same as showBlogs.vue
},
filters:{
// same as showBlogs.vue
},
directives:{
// same as showBlogs.vue
}
}
</script>

<style scoped>
/* same as above */
</style>
-----------------------------------
[src > mixins > searchMixin.js]
export default{
computed:{
filteredBlogs: function(){
return this.blogs.filter((blog) => {
return blog.title.match(this.search) || blog.body.match(this.search);
});
}
}
}

Available to see the full code with syntax highlighting on GitHubGist.


38) Setting Up Routing (YouTube)

Vue Router is the official router for Vue.js. It deeply integrates with Vue.js core to make building Single Page Applications with Vue.js a breeze (official website)”.

Install vue-router with Node Package Manager(NPM) : npm install vue-router --save.

[src > main.js]
import Vue from 'vue'
import App from './App.vue'
import axios from 'axios'
import VueRouter from 'vue-router'
import
Routes from './routes'

Vue.prototype.$http = axios;
Vue.use(VueRouter);

const router = new VueRouter({
routes : Routes
});

new Vue({
el: '#app',
render: h => h(App),
router: router
});
-----------------------------------
[src > routes.js]
import showBlogs from './components/showBlogs.vue';
import addBlog from './components/addBlogs.vue';

export default[
{ path: '/', component: showBlogs },
{ path: '/add', component:
addBlog }
]
-----------------------------------
[src > App.vue]
<template>
<div>
<router-view></router-view>
</div>
</template>
-----------------------------------
[src > components > showBlogs.vue]
<template>
<!-- same as above -->
</template>
<script>
export default{
data(){
blogs: [],
search: ''
},
created(){
// same as above
},
computed:{
filteredBlogs: function(){
return this.blogs.filter((blog) => {
return blog.title.match(this.search) || blog.body.match(this.search);
});
}
},
filters:{
// same as above
},
directives:{
// same as above
}
}
</script>

<style scoped>
/* same as above */
</style>

Available to see the full code with syntax highlighting on GitHubGist.

  • “The <router-view> component is a functional component that renders the matched component for the given path. Components rendered in <router-view> can also contain its own <router-view>, which will render components for nested paths (official website)”.
  • “The default mode for vue-router is hash mode - it uses the URL hash to simulate a full URL so that the page won't be reloaded when the URL changes. (official website)”.
  • Links can be accessed with “#” (e.g., “localhost:8080/#/” & “localhost:8080/#/add”).

39) Routing : Hash vs History (YouTube)

In the hash mode, a request to the server is not made. The hash mode just takes users to a different part of the website by using hash.

To get rid of the hash, we can use the router’s history mode.

[src > main.js]
// same as above

const router = new VueRouter({
routes : Routes,
mode: 'history'
});

new Vue({
// same as above
});

Available to see the full code with syntax highlighting on GitHubGist.

> Now, “localhost:8080/” & “localhost:8080/add” work! (No more need to include a hash tag in URL)


40) Adding Router Links (YouTube)

Let’s add a header at the top with a navigation bar with two links that switch the view between showBlogs.js and addBlog.js.

[src > App.vue]
<template>
<div>
<add-header></add-header>
<router-view></router-view>
</div>
</template>

<script>
import header from './components/header.vue'

export default{
components{
'add-header': header
}
}
</script>
-----------------------------------
[src > components > header.vue]
<template>
<nav>
<ul>
<li><router-link to='/' exact>Blog</router-link></li>
<li><router-link to='/add' exact>Add a New Blog</router-link></li>
</ul>
</nav>
</template>
<style scoped>
ul{
list-style-type: none;
text-align: center;
margin: 0;
}
li{
display: inline-block;
margin: 0 10px;
}
a{
color: #fff;
text-decoration: none;
padding: 6px 8px;
border-radius: 10px;
}
nav{
background: #444;
padding: 14px 0;
margin-bottom: 40px;
}
.router-link-active{
background: #eee;
color: #444;
}

</style>

Available to see the full code with syntax highlighting on GitHubGist.

  1. Instead of <a href='/'>, router-link is used. router-link intercepts the click event. So, we don’t need to re-load the page, and that’s quicker.
  2. A router-link has a class of router-link-active. Styling router-link-active allows us to differentiate between an inactive router-link and an active router-link.
  3. When exact property is not included in the router-link tag, <router-link to='/'> has a style of router-link-active even after <router-link to='/add'> becomes active and <router-link to='/'> becomes inactive. The reason is that '/add' contains '/'. *** Exact property makes a router-link active only when the URL exactly matches the link included in the router-link tag.

41) Route Parameters (YouTube)

“Very often we will need to map routes with the given pattern to the same component. For example, we may have a User component which should be rendered for all users but with different user IDs. In vue-router, we can use a dynamic segment in the path to achieve that.

A dynamic segment is denoted by a colon :. When a route is matched, the value of the dynamic segments will be exposed as this.$route.params in every component. Therefore, we can render the current user ID by updating User's template to this: (official website)”

const User = {
template: '<div>User {{ $route.params.id }}</div>'
}
const router = new VueRouter({
routes: [
// dynamic segments start with a colon
{ path: '/user/:id', component: User }
]
})

In other words, we can detect route parameters and handle them in a component by making a HTTP request for correct resource.

[src > routes.js]
import showBlogs from './components/showBlogs.vue';
import addBlog from './components/addBlogs.vue';
import singleBlog from './components/singleBlog.vue';
export default[
{ path: '/', component: showBlogs },
{ path: '/add', component: addBlog },
{ path: '/blog/:id', component: singleBlog }
]
-----------------------------------
[src > components > singleBlog.vue]
<template>
<div id='single-blog'>
<h1>{{ blog.title }}</h1>
<article>{{ blog.body }}</article>
</div>
</template>
<script>
export default{
data(){
return{
id: this.$route.params.id,
blog: {}

}
},
created(){
const axios = require('axios');
axios.get('https://jsonplaceholder.typicode.com/posts/' + this.id
).then(response => {
console.log(response);
this.blog = response.data;
});
}
}
</script>
<style scoped>
#single-blog{
max-width: 960px;
margin: 0 auto;
color: gray;
}
</style>

There are a few differences between my code and Net Ninja’s code, since I used axios and Net Ninja used vue-resource.

  1. Use import axios from ‘axios’ instead of import VueResource from 'vue-resource’ in main.js file.
  2. Enter Vue.prototype.$http = axios instead of Vue.use(VueResource).
  3. Inside of post: function(), include const axios = require(‘axios').
  4. Type axios.post instead of this.$http.post.
  5. Use => instead of function().

[Net Ninja’s code]

.then(function(data) {
console.log(data);
this.blog = data.body;

[My code]

.then(response => {
console.log(response);
this.blog = response.data;

> In order to access sample objects provided by JSON Placeholder, I needed to use data instead of body. So, not to be confused with that, I passed down response instead of data.


/blog/<a number> displays a different object provided by JSON Placeholder. (e.g., localhost:8080/blog/30)

But, users will not type URL like that to access a webpage. Users will read blog articles and click one of them to access specific blog article.

So, replaced <h2 v-rainbow>{{ blog.title | to-uppercase }}</h2> in showBlogs.vue with the following:

<router-link v-bind:to="'/blog' + blog.id"><h2 v-rainbow>{{ blog.title | to-uppercase }}</h2></router-link>

Available to see the full code with syntax highlighting on GitHubGist.


42) Posting to Firebase (YouTube)

So far, we’ve used fake online REST API provided by JSON Placeholder. We can add our own content, store it in a database, and retrieve it by using a tool called “Firebase”. Firebase lets us store data in a NoSQL(Structured Query Language) database, which means we’re storing data as JavaScript objects.

After you create a project, you will be directed to the project page. On the project page, click the followings in order: “database” icon on the left, “Realtime Database” in the middle > “Rules” tab.

If the default setting doesn’t look like the following, change the setting like the following:

{
"rules": {
".read": true,
".write": true
}
}

> ".read" stands for whether data is allowed to be read by users or not.

> ".write" stands for whether data is allowed to be written or not.

*** After you put your app into production, you’d want to set up the security for your app. Please visit here to learn more about firebase security rules.

Under the “data” tab, you can see the link of Firebase database for your project. we’d use it instead of the JSON Placeholder link : https://jsonplaceholder.typicode.com/posts/.

[src > components > addBlog.vue]
<template>
<!-- same as above -->
</template>
<script>
export default{
data(){
// same as above
},
methods:{
post: function(){
const axios = require('axios');
axios.post('https://<name of your project>.firebaseio.com/posts.json', this.blog
).then(response => {
console.log(response);
this.submitted = true;
});
}
}
}
</script>
<style scoped>
/* same as above */
</style>

Available to see code with syntax highlighting on GitHubGist.

> There are a few differences between my code and Net Ninja’s code, since I used axios and Net Ninja used vue-resource. If you like to see the details of that again, please check out “31) HTTP Requests” chapter at the beginning of this blog post.

Before moving on, add a few blog posts under the “Add a New Blog” tab to retrieve data from Firebase database for the next chapter’s exercise.


43) Retrieving Posts from Firebase (YouTube)

We still see sample data from JSON Placeholder. In order to see blog posts we added to firebase, we need to take some steps.

[STEP 1] : Check data we get from Firebase on console (in showBlogs.vue)

created():{
post: function(){
const axios = require('axios');
axios.get('https://<name of your project>.firebaseio.com/posts.json')
.then(response => {
console.log('1. response', response);
})
}
}

[STEP 2] : Add id property (in showBlogs.vue)

In Chapter 41(Adding Router Links), we added a link to each individual blog post : <router-link v-bind:to=”’/blog’ + blog.id”>.

The id property existed in the sample data. But, it doesn’t exist in our data from Firebase. However, we have a unique key for each object which refers to a blog post.

[STEP 2–1] : Return promise objects (in showBlogs.vue)

created():{
post: function(){
const axios = require('axios');
axios.get('https://<name of your project>.firebaseio.com/posts.json')
.then(response => {
return response.data;
});
}
}

> “The Promise object represents the eventual completion (or failure) of an asynchronous operation, and its resulting value” (MDN). Because we’re dealing with promise objects, the objects are asynchronous and we need to use .then method.

[Net Ninja’s code]

.then(function(data) {
return data.json();

[My code]

.then(response => {
return response.data;

Since Net Ninja used vue-resource, he used .json() to convert data into JSON data. But, I used axios. So I didn’t need to do that.

> In axios, we no longer need to convert data into JSON data. One of features of axios is “automatic transforms for JSON data” (GitHub).

[STEP 2–2] : Fire a call-back function (in showBlogs.vue)

created():{
post: function(){
const axios = require('axios');
axios.get('https://<name of your project>.firebaseio.com/posts.json')
.then(response => {
console.log('2. response.data', response.data);
return response.data;
}).then(response => {
console.log('3. response / callback function', response);
});
}
}

We can now use .then method, which fires a call-back function after response.data is executed.

[STEP 2–3] : Cycle through objects (in showBlogs.vue)

created():{
post: function(){
const axios = require('axios');
axios.get('https://<name of your project>.firebaseio.com/posts.json')
.then(response => {
return response.data;
}).then(response => {
let blogsArray = [];
for(let key in response){
console.log('4. key', key);
console.log('5. response[key]', response[key]);
}
});
}
}

[STEP 2–4] : Push the objects into an empty array (in showBlogs.vue)

  1. Add a property called “id” to each object, which would be equal to the key.
  2. Push all objects to the empty array we created : blogsArray.
created(){
axios.get('https://<name of your project>.firebaseio.com/posts.json')
.then(response => {
return response.data;
}).then(response => {
let blogsArray = [];
for(let key in response){
response[key].id = key;
blogsArray.push(response[key]);

}
});
}
}

[STEP 2–5] : Display the objects on the screen (in showBlogs.vue)

  1. After pushing all objects into the blogsArray, assign the array to this.blogs array. (This.blogs array is what’s shown on the screen.)
  2. There’d be still an error, because we’ve used blog.body to retrieve contents in sample data from JSON Placeholder. To retrieve contents in our data from Firebase, we need to change blog.body to blog.content in searchMixins.js, showBlogs.vue, and singleBlog.vue.
data(){
return { blogs: [], search: '' }
},
created(){
axios.get('https://<name of your project>.firebaseio.com/posts.json')
.then(response => {
return response.data;
}).then(response => {
let blogsArray = [];
for(let key in response){
response[key].id = key;
blogsArray.push(response[key]);

}
console.log('6. this.blogs', this.blogs);
console.log('7. blogsArray', blogsArray);
this.blogs = blogsArray;
});
}
}

[STEP 3] : Display a single blog post in a new page when clicked (in singleBlog.vue)

data(){
return {
id: this.$route.params.id,
blog: {}
}
},
created(){
axios.get('https://<name of your project>.firebaseio.com/posts/' + this.id + '.json')
.then(response => {
return response.data;
}).then(response => {
this.blog = response;
});
}
}

Since we created id by using key in Step 2, we can use that to open a single blog post in a new page when clicked.

Available to see the full code with syntax highlighting on GitHubGist.


If you’d like to read the previous parts of my summary of Vue JS2 Tutorial by Net Ninja, please visit here for part 1 & here for part 2.


Thanks for reading! 💕 If you like this blog post, please clap👏

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade