Reputation: 2504
I'm trying to learn Vue. I read this tutorial and I'm trying to split it in single file components using the standard vue-cli webpack template. I don't have any error in console but the page is white, and I cannot understand why.
This is my main.js file
import Vue from 'vue'
import App from './App'
Vue.config.productionTip = false
window.axios = require('axios');
const NYTBaseUrl = "https://api.nytimes.com/svc/topstories/v2/";
const ApiKey = "18e1540d187c4b46bae767782750f9fd";
const SECTIONS = "home, arts, automobiles, books, business, fashion, food, health, insider, magazine, movies, national, nyregion, obituaries, opinion, politics, realestate, science, sports, sundayreview, technology, theater, tmagazine, travel, upshot, world";
function buildUrl (url) {
return NYTBaseUrl + url + ".json?api-key=" + ApiKey
}
const vm = new Vue({
el: '#app',
data: {
results: [],
sections: SECTIONS.split(', '), // create an array of the sections
section: 'home', // set default section to 'home'
loading: true,
title: ''
},
mounted () {
this.getPosts('home');
},
methods: {
getPosts(section) {
let url = buildUrl(section);
axios.get(url).then((response) => {
this.loading = false;
this.results = response.data.results;
let title = this.section !== 'home' ? "Top stories in '"+ this.section + "' today" : "Top stories today";
this.title = title + "(" + response.data.num_results+ ")";
}).catch((error) => { console.log(error); });
}
}
});
And this is the App.vue file
<template>
<div id="app">
<h1>Test</h1>
<product-list></product-list>
</div>
</template>
<script>
import Products from './components/Products'
export default {
name: 'app',
components: {
Products
}
}
</script>
<style lang="sass" >
@import '~bulma/sass/utilities/initial-variables.sass'
@import "~bulma/sass/utilities/_all"
@import "~bulma/sass/base/_all"
@import "~bulma/sass/grid/columns"
@import "~bulma/sass/components/_all"
</style>
I also create a Products.vue file in the components folder
<template id="product-list">
<section>
<div class="row" v-for="posts in processedPosts">
<div class="columns large-3 medium-6" v-for="post in posts">
<div class="card">
<div class="card-divider">
{{ post.title }}
</div>
<a :href="post.url" target="_blank"><img :src="post.image_url"></a>
<div class="card-section">
<p>{{ post.abstract }}</p>
</div>
</div>
</div>
</div>
</section>
</template>
Vue.component('Products', {
props: ['results'],
template: "#product-list",
computed: {
processedPosts() {
let posts = this.results;
// Add image_url attribute
posts.map(post => {
let imgObj = post.multimedia.find(media => media.format === "superJumbo");
post.image_url = imgObj ? imgObj.url : "http://placehold.it/300x200?text=N/A";
});
// Put Array into Chunks
let i, j, chunkedArray = [],
chunk = 4;
for (i = 0, j = 0; i < posts.length; i += chunk, j++) {
chunkedArray[j] = posts.slice(i, i + chunk);
}
return chunkedArray;
}
}
});
Everything looks fine for me (except for the window.axios = require('axios');
that I don't understand why is not present in the original tutorial) but the page is blank and also the tag I add for debug is not present in the DOM.
Edit
Looks like the code is not compiled.
My page source code is
<body>
<div id="app"></div>
<!-- built files will be auto injected -->
<script type="text/javascript" src="/app.js"></script>
</body>
** Edit 2 **
I understand the problem. This is my index.html.
Upvotes: 6
Views: 25788
Reputation: 3517
There are several issues with your codes. First you have to wrap JavaScript in a script
tag on your Products.vue
file. Also on your Products.vue
file you could just export the component files instead of creating the way you did, also you haven't imported Vue
on Products.vue
file but you are using it Vue.component('Products', {})
. You should create Products.vue
file this way
Products.vue
<template>
<section>
<div class="container" v-for="posts in processedPosts">
<div class="columns" v-for="post in posts">
<div class="column is-6 is-offset-3">
<div class="card">
<header class="card-header">
<p class="card-header-title">
{{ post.title }}
</p>
</header>
<div class="card-image">
<a :href="post.url" target="_blank">
<figure class="image">
<img :src="post.image_url">
</figure>
</a>
</div>
<div class="card-content">
<div class="content">
<p>{{ post.abstract }}</p>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
</template>
<script>
export default{
props: ['results'],
computed: {
processedPosts() {
let posts = this.results;
// Add image_url attribute
posts.map(post => {
let imgObj = post.multimedia.find(media => media.format === "superJumbo");
post.image_url = imgObj ? imgObj.url : "http://placehold.it/300x200?text=N/A";
});
// Put Array into Chunks
let i, j, chunkedArray = [],
chunk = 4;
for (i = 0, j = 0; i < posts.length; i += chunk, j++) {
chunkedArray[j] = posts.slice(i, i + chunk);
}
return chunkedArray;
}
}
}
</script>
On your main.js
file you forgot to mount <App />
template.
new Vue({
el: '#app',
template: '<App/>',
components: { App },
})
You should also move code for network request, components to App.vue
file.
main.js
import Vue from 'vue'
import App from './App'
Vue.config.productionTip = false
window.axios = require('axios');
new Vue({
el: '#app',
template: '<App/>',
components: { App },
})
Have to use the component we are importing, on your code you imported Products
but using <product-list></product-list>
.
App.vue
<template>
<div id="app">
<products :results="results"></products>
</div>
</template>
<script>
import Products from './components/Products'
const NYTBaseUrl = "https://api.nytimes.com/svc/topstories/v2/";
const ApiKey = "18e1540d187c4b46bae767782750f9fd";
const SECTIONS = "home, arts, automobiles, books, business, fashion, food, health, insider, magazine, movies, national, nyregion, obituaries, opinion, politics, realestate, science, sports, sundayreview, technology, theater, tmagazine, travel, upshot, world";
function buildUrl (url) {
return NYTBaseUrl + url + ".json?api-key=" + ApiKey
}
export default {
name: 'app',
data: function(){
return {
results: [],
sections: SECTIONS.split(', '), // create an array of the sections
section: 'home', // set default section to 'home'
loading: true,
title: ''
}
},
components: {
Products
},
mounted(){
this.getPosts('home');
},
methods:{
getPosts(section) {
let url = buildUrl(section);
axios.get(url).then((response) => {
this.loading = false;
this.results = response.data.results;
let title = this.section !== 'home' ? "Top stories in '"+ this.section + "' today" : "Top stories today";
this.title = title + "(" + response.data.num_results+ ")";
}).catch((error) => { console.log(error); });
}
}
}
</script>
I tested this out, and uploaded code to github https://github.com/azs06/vuejs-news, you can clone it and check it out. Here it is deployed http://noisy-coach.surge.sh/
Note: I am using the api key temporarily will remove it, as soon as you test it out.
Upvotes: 10
Reputation: 2070
Next time to debug your code - first you should take a look at browser console for errors.
You can see full code of this tutorial here - https://github.com/sitepoint-editors/vuejs-news Just make sure you write code like it's shown on github files.
Upvotes: -2