Thomas Amal
Thomas Amal

Reputation: 23

Vue js component not rendering data without page refresh

I need to display jsonp callback data only on a readings component. I am dynamically adding the js script to the html head on loading the readings component. The data from the callback function is displaying on the page. But when I move to the home route and come back to the readings route, the data from the callback is not displayed. The data is displayed only on refreshing the web page. This is the callback function script:

mounted() {
      this.fetchData()    
    }, 

    methods: {
      fetchData() {        
        let universalisScript = document.createElement('script');
        universalisScript.setAttribute('type', 'application/javascript');
        universalisScript.setAttribute('src', "/js/universalis.js"),
        universalisScript.setAttribute('src', "/js/universalis.js"),
        universalisScript.async = true,
        document.head.appendChild(universalisScript),
        document.head.removeChild(universalisScript);
      }
    }

Can someone guide me, what is to be done to get the data displayed without page refresh

Upvotes: 0

Views: 5976

Answers (1)

YuuwakU
YuuwakU

Reputation: 71

Let us break it down to why it is failing, why you should not take this approach and what can you do to solve it.

Why it is failing? There is only one reason for failing is because javascript in script tags will run from top to bottom, hence, your callback will only run once for each page load. The routes changing are done programatically and not an actual change of the page, that's why it is called a Single Page Application(SPA), because everything happens on one page.

Why you should not take this approach? Because each time your reading component mounts, it is adding a script tag to the head, which won't execute at all as the page has already loaded.

What can you do to solve it? Use Nuxt.js, after going through this, you will understand what are page components. Now page components can be loaded asynchronously, hence, you can create a reading page component, populate it's data property from the payload you receive from an API and pass that to your reading component prop, as so:

If you're using Nuxt.js

<template>
  <div>
    <readings :readings-data="universalisData" />
  </div>
</template>
<script>
import Readings from '@/components/Reading'
import axios from 'axios'
import adapter from 'axios-jsonp'

export default {
  components: {
   Readings,
  },
  asyncData() { // This is a Nuxt.js feature and not a vue feature
    return axios({ url: 
      'universalis.com/Asia.India/20190124/jsonpmass.js',
       adapter: jsonpAdapter,
       callbackParamName: 'universalisCallback' })
    .then(response => {
      /**
       The following return will pre populate the data property of the
       vue component without any explicit defining of 'universalisData'
       in the data property.
      **/
      return { universalisData: response }
     })
    .catch(error => {
      return {}
     })
   },
   data() {
    return {
     // No need to set 'universalIsData' if you populate from asyncData 
    }
   }

}
</script>

If you're using only Vue

<template>
  <div>
    <readings :readings-data="universalisData" />
  </div>
</template>
<script>
import Readings from '@/components/Reading'
import axios from 'axios'
import adapter from 'axios-jsonp'

export default {
  components: {
   Readings,
  },
  data() {
   return {
     universalisData: {},
    }
  }
  methods: {
   getUniversalisData() {
    return axios({ url: 
      'universalis.com/Asia.India/20190124/jsonpmass.js',
       adapter: jsonpAdapter,
       callbackParamName: 'universalisCallback' })
    .then(response => {
      return response
     })
    .catch(error => {
      return {}
     })
   },
  },
   created() { // or any other lifecycle event you want to listen to as per your discernment
     this.getUniversalisData()
       .then(response => {
         this.universalisData = response
       })
       .catch(error => {
         this.universalisData = {}
       })
   }
}
</script>

This way, each time your readings page component loads, and not a page refresh, it will fetch the readings data, populate the data property of the page component and you can pass it to the prop of your readings components. But remember asyncData only works for the page components and not for any component in Nuxt.js.

Upvotes: 2

Related Questions