I have recently developed a component that showcases previews of blog articles. This particular component includes pagination functionality, where selecting a new page triggers the refreshment of the article previews array. The list of articles is obtained from a JSON api on server1, which contains information necessary to fetch each individual article from server 2. Subsequently, x asynchronous fetches are fired off to server 2, matching the number of items in the first response. Upon receiving these responses, the items in the array are then updated.
Being relatively new to vue, I initially faced some challenges but managed to get everything working smoothly. Currently, my focus is on incorporating a spinner within the article previews while the separate articles are loading. My initial approach was to monitor an article update within the preview component and display the spinner accordingly. However, this does not seem to work as expected and has led me to question the implementation. Despite noticing that the watch in the preview component is not being called for every instance, the updates and displays function correctly. I suspect this inconsistency may be attributed to the messaging system, but so far, I haven't been able to rectify it.
My query encompasses two aspects:
- Is my existing implementation an appropriate means of addressing this issue? To achieve seamless operation, I found it necessary to 'erase' the array to prevent new articles from 'overwriting' old ones, thus ensuring visibility.
- How can I effectively manage the spinners? Why aren't the watches triggering, and what steps can be taken to resolve this matter? Within the provided code snippet below, you'll find some console logs detailing discrepancies observed during testing - specifically noting 'async' appearing 10 times and varying occurrences of 'watch', never consistently at 10 instances.
The complete code repository can be accessed on github via the following links: Home and ArticlePreview. These sections encompass the most crucial excerpts:
Home:
<template>
<div class="container article">
<div class="row" v-for="(article, index) in articles" :key="index">
<ArticlePreview v-bind:blogEntry="article"></ArticlePreview>
</div>
<b-pagination-nav :use-router="true" :link-gen="generateLink" align="center" :number-of-pages="nofPages" v-model="pageIndex" />
</div>
</template>
data: function ()
{
return {
articles: <BlogEntry[]> [],
nofPages: 1
}
},
loadContent()
{
fetch("./api/v1/articles.php?page=" + this.pageIndex)
.then(response => response.json())
.then((data) =>
{
this.nofPages = Math.ceil(data.nofItems/10);
this.articles.splice(0);
this.articles.splice(data.data.length);
let index :number;
for(index = 0; index < data.data.length; index++)
{
createArticleAsync(data.data[index].name, data.data[index].permlink).then(function(this: any, index: number, article: BlogEntry)
{
console.log('async');
Vue.set(this.articles, index, article);
}.bind(this, index));
}
})
},
ArticlePreview:
<template>
<div class="container-fluid">
<div class="row" v-if="blogEntry">
<template v-if="blogEntry">
<div class="imageframe col-md-3">
<div class="blog-image">
<img :src="blogEntry.previewImage" style="border-radius: 5px;">
</div>
</div>
<div class="col-md-9">
<h5 class="font-weight-bold" style="margin-top:5px;"><router-link :to="{ name: 'Article', params: {author: blogEntry.author, permlink: blogEntry.permlink } }">{{blogEntry.title}}</router-link></h5>
<div class="multiline-ellipsis">
<p>{{blogEntry.previewBody}}</p>
</div>
<span class="metadata"><i>by <a :href="AuthorBlogLink">{{blogEntry.author}}</a> on {{blogEntry.created | formatDate}}</i></span>
</div>
</template>
<template v-else>
<p>Loading</p>
</template>
</div>
</div>
</template>
<script lang="ts">
import Vue from "vue";
import VueRouter from 'vue-router';
import {formatDate} from "../utils/utils";
export default Vue.extend({
props: [
'blogEntry'
],
data: function ()
{
return {
loading: true
}
},
watch:
{
blogEntry(newValue)
{
console.log('watch');
if(newValue)
this.loading = false;
else
this.loading = true;
}
}
});
</script>