Building A News Aggregation Application Using VueJs
Ohidoa Oluwatobi Samuel
Posted on December 9, 2017
So lately I've been experimenting alot with VueJs and trying to implement almost anything I can think of in VueJs. So this is what I came up with.
In this article we will be building a news aggregation application, what the application basically does is, it allows you to select a news vendor from a list of vendors,retrieves news from the selected vendor and displays the news on the web application. Enough of the talk lets get started.
We will be using the Vue-cli to generate a startup template for our Vue application. This is a tool for rapid application development as it creates a basic schema of a Vue application.
But firstly we need to install Vue and Vue-cli.
- This project assumes base knowledge of javascript and it also assumes you have an API key with newsapi.org if not please visit newsapi.org to get an API key before continuing.
To install Vue, Vue-cli and Vue-resource lets type in this commands into our terminal.
$ npm install vue
$ npm install vue-resource
$ npm install --global vue-cli
Having done that we need to create/navigate into our working directory and run the following command
$ vue-init webpack-simple
The above command will create a new application with the webpack-simple template, The webpack-simple template comes packed with some features such as hot-reload, vue-loader e.t.c you can read more regarding weback templates from vue-js documentation website.
In your current working directory where you run the vue-init command enter the following command.
# install dependencies and go!
$ npm install
$ npm run dev
After Entering the command we should be good to go. Let's begin coding the application.
Basically the application will be having two components aside the root component, the News component and the SelectNews components.
The News Component will control the the look and feel of each news article on the webpage while the SelectNews component would control the interface for selecting the news vendor.
Lets begin with the root component App.vue.
We have to import our child components [selectNews, news] into our Root component App.vue .
import Selectnews from './components/selectNews'
import News from './components/news'
Then we register the imported components as children of the root component.
export default {
name: 'app',
components:{
'select-news':Selectnews,
'news':News
},
data () {
return {
source:'',
articles:[]
}
}
Also in the template section of our App.vue component we need to specify where we want our child components to appear.
<div class="container" id="main_container">
<select-news v-on:newVendor="newVendor"/>
<news :articles="articles"/>
</div>
In our markup you will notice the use of the v-on directive, it is used to attach event listeners to a Vue element. in the above markup we are listening for the newVendor event on the select-news component. Note: This is a custom event we will be using in this application. this event is triggered on the select-news component and is handled here on the root component.
Basically what we are doing here is we are bubling the newVendor event from the select-news component and using the $http method which is made available to us via the vue-resource we pulled in earlier.
methods:{
newVendor:function(value){
this.source=value;
this.$http.get('https://newsapi.org/v2/top-headlines?
sources='+this.source+'&apiKey={your api key}')
.then(function(response){
return JSON.parse(response.bodyText);
})
.then(function(response){
this.articles=response.articles;
})
.catch(function(err){
console.log(err);
})
}
}
Now lets head out to the selectNews component and see what we got.
The markup for the selectNews component is shown bellow
<select name="country" @change="sourceChanged">
<option v-for="(source,index) in sources" :key="index"
:value="source.name">{{source.name}} </option>
</select>
<div v-if="source" class="selectFooter">
<p class="vendor-information">
{{ source.description }}
</p>
<p class="controls"> <a class="button is-primary" target="_blank"
:href="source.url"> Visit Vendor's Website</a> </p>
</div>
<script>
export default {
name: 'selectNews',
data () {
return {
description:'',
sources:[],
source:''
}
},
methods:{
sourceChanged:function(evt){
var that=this;
Object.values(this.sources).map(function(elem,index){
if(elem.name==evt.target.value){
that.source=elem;
}
});
this.$emit('newVendor',this.source.id);
}
},
created:function(){
this.$http.get('https://newsapi.org/v1/sources?language=en')
.then(function(response){
if(response.body.status!='ok'){
throw new Error('Could not fetch the list of supported sources');
}
return JSON.parse(response.bodyText);
}).then(function(response){
this.sources=response.sources;
}).catch(function(err){
console.log(err.stack);
});
}
}
</script>
In the above markup the souceChanged function is called whenever a new vendor is selected from the dropdown list and what this function basically does is to collect the unique identifier of the selected vendor and then emit a custom event called newVendor which we would catch and handle in the root/parent component.
the created function above is one of the many life-cycle hooks Vue provide us with and this method runs before the component is mounted and this is a really nice place to perform any operations/logic needed in the component e.g Api calls as we did above.
Having done that, now lets examine the code for the news component.
below is the mark up
<ul class="container is-semi-fluid">
<li v-for="article in articles" :key="article.url" class="notification">
<article class="media">
<figure class="media-left">
<a :href="article.url" class="image is-128x128" target="_blank">
<img :src="article.urlToImage">
</a>
</figure>
<div class="media-content">
<div class="content">
<p>
<strong>{{article.title}}</strong>
<br>
{{article.description}}
</p>
</div>
<nav class="level is-mobile">
<div class="level-left">
<a class="level-item">
<span class="icon is-small"><i class="fa fa-reply"></i></span>
</a>
<a class="level-item">
<span class="icon is-small"><i class="fa fa-retweet"></i></span>
</a>
<a class="level-item">
<span class="icon is-small"><i class="fa fa-heart"></i></span>
</a>
</div>
</nav>
</div>
</article>
</li>
</ul>
In the above mark up we looped through a list of news article using the v-for directive. what this basically does is it allows us to repeat the same markup enclosed within the parent element i.e the element containing the v-for element,
and then we can use the data returned on each iteration within the list item block.
Now lets examine the script section of this component
<script>
export default {
name: 'news',
props: ['articles'],
data () {
return {
}
}
}
</script>
We basically just accept a prop called articles which is an array from the root component and then loop through the array and output individual contents.
So, having followed through this article we should have a working prototype of the news aggregation application. We can style according to individual preference and then its ready for testing.
complete source-code for this project is available here in my github repo
Posted on December 9, 2017
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.