Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vue rendering array of objects

I'm creating a basic app in vue that uses axios to make a get request to grab html data from a blog site and using the cheerio node package to scrape the site for elements such as blog title and the date posted of each blog articles. However, I'm having trouble trying to render the scraped elements into the html. Here's the code:

<template>
  <div class="card">
    <div 
      v-for="result in results"
      :key="result.id" 
      class="card-body">
      <h5 class="card-title">{{ result.title }}</h5>
      <h6 class="card-subtitle mb-2 text-muted">{{ result.datePosted }}</h6>
    </div>
  </div>
</template>

<script>
const Vue = require('vue')
const axios = require('axios')
const cheerio = require('cheerio')
const URL = 'https://someblogsite.com'

export default {
  data() {
    return {
      results: []
    }
  },
  mounted: function() {
    this.loadBlogs()
  },
  methods: {
    loadBlogs: function() {
      axios
        .get(URL)
        .then(({ data }) => {
          const $ = cheerio.load(data)
          let results = this
          $('.post').each((i, element) => {
            const title = $(element)
              .children('.content-inner')
              .children('.post-header')
              .children('.post-title')
              .children('a')
              .text()
            const datePosted = $(element)
              .children('.content-inner')
              .children('.post-header')
              .children('.post-meta')
              .children('.posted-on')
              .children('a')
              .children('.published')
              .text()
            this.results[i] = {
              id: i + 1,
              title: title,
              datePosted: datePosted
            }
          })
        })
        .catch(console.error)
    }
  }
}
</script>

I tried declaring

let results = this

before the axios request to refer to the scope within export default, but still getting the indicator from VS Code that the scope is still within the loadBlogs function. Am I missing something? I greatly appreciate the help! Thanks!

like image 281
Artawood Avatar asked Sep 12 '26 15:09

Artawood


1 Answers

I think your problem is that you're trying to set Property of an results array so Vue can't pick your data update. Instead you should construct new array from your parsed page and set it as this.results = newResultsArray:

loadBlogs: function() {
    axios.get(URL).then(({data}) => {
        const $ = cheerio.load(data)
        const newResults = $('.post').map((i, element) => {
            const title = $(element).children('.content-inner .post-header .post-title a').text()
            const datePosted = $(element).children('.content-inner .post-header .post-meta .posted-on a .published').text()
            return {
                id: i + 1,
                title: title,
                datePosted: datePosted
            }
        })//.toArray() // this toArray call might be needed, I haven't worked with cheerio for some time and not sure whether it returns array or its own collection type like jQuery does
        this.results = newResults;
    }).catch(console.error)
}

Also it should be even simpler if you just use this.results.push({...}) instead of property assignment this.results[i] = {...} (but it is usually easier to handle whole arrays instead of inserting and removing parts of them, both are viable solutions in their respective use cases, though).

And please check out this documentation article about how Vue handles reactive updates, it describes the problem you've encountered.

like image 171
Azriel Gridfen Avatar answered Sep 14 '26 13:09

Azriel Gridfen