How can I get data from json file using vue js 2? - javascript

I am trying to get data from json file, it has just json data.
[{"id":81,"body":"There are some reason to fix the issues","created_at":"2017-11-16 11:56:47","updated_at":"2017-11-16 11:56:47"}]
I added vue-resource and properly use it as per vue syntax.
import vueResource from 'vue-resource'
Vue.use(vueResource)
In my userlist component i am trying following script
export default {
data:function(){
return {
list:[],
car:{
id:'',
body:''
}
};
},
created: function(){
this.fetchCarList();
},
methods:{
fetchCarList: function(){
this.$http.get('http://localhost:8080/api.js').then(function(response){
this.list = response.data
});
}
}
}
And this is component HTML loop
<ul id="example-1">
<li v-for="item in list">
{{ item.body }}
</li>
</ul>
I have checked http://localhost:8080/api.js which is properly returning the data. Also when I am adding the json data in fetchCarList method then loop works fine but with get() call it does not working.
How can I solve the issue?

You have a scoping issue: this within the callback does not refer to your Vue instance. That is because you are not using ES6 arrow function, i.e.:
this.$http.get('http://localhost:8080/api.js').then(response => {
this.list = response.data
});
...which means the outer this is not passed in. You will have to proxy that yourself, i.e. var self = this on the outside, and then use self.list = response.data:
var self = this;
this.$http.get('http://localhost:8080/api.js').then(response => {
self.list = response.data
});

Related

Vue prefetch data from separate backend

I have some queries from an API-Server that returns a json object that will be static over a user session, but not static forever.
It's a one-pager with Vue router.
How can I achieve that I:
can access this.myGlobals (or similar eg window.myGlobals) in all components, where my prefetched json-data from API-Server is stored.
My approach that is already working is to embed help.js via a mixin.
Oddly enough, I get hundreds of calls to this query. At first I thought that it only happened in the frontend and is chached, but the requests are actually sent hundreds of times to the server. I think it is a mistake of my thinking, or a systematic mistake.
i think the problem is, that the helper.js is not static living on the vue instance
main.js:
import helpers from './helpers'
Vue.mixin(helpers)
helpers.js:
export default {
data: function () {
return {
globals: {},
}
}, methods: {
//some global helper funktions
},
}, mounted() {
let url1 = window.datahost + "/myDataToStore"
this.$http.get(url1).then(response => {
console.log("call")
this.globals.myData = response.data
});
}
}
log in console:
call
SomeOtherStuff
(31) call
SomeOtherStuff
(2) call
....
log on server:
call
call
call (pew pew)
My next idea would be to learn vuex, but since its a easy problem, im not sure if i really need that bomb ?
You can use plugin to achieve this.
// my-plugin.js
export default {
install (Vue, options) {
// start fetching data right after install
let url1 = window.datahost + "/myDataToStore"
let myData
Vue.$http.get(url1).then(response => {
console.log("call")
myData = response.data
})
// inject via global mixin
Vue.mixin({
computed: {
myData () {
return myData
}
}
})
// or inject via instance property
Vue.prototype.$myData = myData
// or if you want to wait until myData is available
Vue.prototype.$myData = Vue.$http.get(url1)
.then(response => {
console.log("call")
myData = response.data
})
}
}
and use it:
Vue.use(VueResource)
Vue.use(myPlugin)

Assigning res.data to variable returns null

I am trying to make a GET request to an API, assign the response to a variable and console.log it. Currently I get null in the console and I don't know why. when I just console.log the res.data I get the data, but for some reason the value does not get assigned to the variable allBeers, how can I save the response to that variable and use it?
Here is my code:
<script>
import axios from "axios";
export default {
name: "BeerList",
data() {
return {
allBeers: null
};
},
created() {
axios.get("https://api.punkapi.com/v2/beers").then(res => {
this.allBeers = res.data;
});
console.log(this.allBeers);
}
};
</script>
Try this solution. axios.get is a promise, and console.log will happen before axios.get is completed. That's why you get null.
<script>
import axios from "axios";
export default {
name: "BeerList",
data() {
return {
allBeers: null
};
},
created() {
axios.get("https://api.punkapi.com/v2/beers").then(res => {
this.allBeers = res.data;
console.log(this.allBeers);
});
}
};
</script>
You are saving the response to 'allBeers' variable correctly. The "how to use it" part depends on what you want to do with the data. Vue's 'data' is reactive, so if you want to print it to console when it changes you should use Vue's watcher in your component:
watch: {
allBeers: function(value) {
console.log("my new beers:");
console.log(value);
}
}
As Vue is UI framework you might want to update your html with the new data, in which case you need to add html template to your component - it will be automatically re-rendered when 'allBeers' change:
template: `<span> {{ allBeers }} </span>`

Is it possible for Vue.js to automatically update the view when a third-party JSON is updated?

I'm trying to accomplish the following but I don't even know if it is even possible with Vue as I'm struggling to get the desired result:
I have an endpoint for an API which returns many objects within an array.
I am successfully rendering the data within my Vue application but I wanted to know if it is possible for Vue to "track" when the array has been updated with more objects and then render those in the view.
I am using setInterval to perform a GET request every 10 minutes and the new data is going into the object within my data() correctly but the changes are not reflected within the view.
At the moment I am changing a boolean from true to false at the beginning and end respectively so that the view is rendered again with v-if.
My goal is to create a simple Twitter feed app that performs a GET request every 10 minutes, collects the tweets, puts them into my Vue instance and show them in the view without having to reload the page/re-render the component. Like an automatic Twitter feed that just constantly loads new tweets every 10 minutes.
Is this even possible? I've tried using the Vue.set() method but that hasn't made any difference.
If it's not possible, what would be the best way to implement something similar?
Here is my code:
JavaScript:
new Vue({
el: '#app',
data: {
items: [],
},
created() {
this.load();
setInterval(() => this.load(), 5000);
},
methods: {
load() {
axios.get('https://reqres.in/api/users?page=2')
.then(response => {
this.items = response.data.data;
});
}
}
});
HTML
<div id="app">
<p v-for="item in items">
{{ item.first_name }}
</p>
</div>
CodePen: https://codepen.io/tomhartley97/pen/VwZpZNG
In the above code, if the array is updated by the GET request, the chances are not reflected within the view?
Yes it is possible. The way you need to set new reactive properties in your Vue instance is the following:
For Object properties: Vue.set(this.baseObject, key, value)
The baseObject cannot be a Vue instance or the base data() object, so you will have to declare a container property.
For Array entries use native array methods: e.g. Array.prototype.push().
Using Vue.set(array, arrayIndex, newArrayElement) does not work
Hence, your solution might look something line that:
<script>
export default {
data() {
return {
response: [],
};
},
mounted() {
setInterval = (() => this.getData), 600000);
}
methods: {
async getData() {
const res = await request();
const resLength = res.data.length;
for (let i = 0; i < resLength; i++) {
// check if entry is already in array
const entryExists = this.response.some((entry) => {
return entry.id === res.data[i].id
})
if (!entryExists) {
// this will make the array entries responsive, but not nested Objects
this.response.push(res.data[i]);
// to create nested responsive Objects you will have to set them explicitly
// e.g. Vue.set(this.response[this.response.indexOf(res.data[i])], nestedObjectKey, res.data[i].nestedObject)
}
}
}
}
};
</script>
Well, I view the codepen, I known why your view do not get update: the api response always return the same array!
Try to return different data.
The api returns an array, so the data defines
data() {
return {
array: [] // array that api returns
}
}
The template may look like this
<div v-for="item in array">
</div>
And the update methods
update() {
setInterval(async () => {
let resp = await api()
this.array = resp.data.concat(this.array)
}, TEN_MINUTES)
}

Parsing input properties in a vue component

I feel like I am running out of ideas on how to solve this issue.
So I have a component that should read a file and display some data from that file. I want to pass only the filename to component so that it can handle reading and parsing the file. To do this I added a property to the component.
The issue I seem to have is that I can't really access that property from the data function, and if I add a watcher on the property I can parse the file as expected, but I can't seem to get that data into the DOM.
This is what I have right now:
<template>
<main :key="fileName">
fileName: {{fileName}}
<div class="post">{{data}}</div>
<div class="info">
<div v-for="item in info" v-bind:key="item.name">{{item.name}}</div>
</div>
</main>
</template>
<script>
const { parse } = require("#/service/parser");
const fs = require("fs");
let postInfo = { data: "abc", info: [] };
export default {
props: ["fileName"],
watch: {
fileName: {
immediate: true,
handler: (newVal, oldVal) => {
if (newVal) {
postInfo = parse(
fs
.readFileSync(__dirname + "/../../assets/" + newVal, "utf8")
.split("\n")
);
}
}
}
},
data: () => {
return postInfo;
}
};
</script>
I am obviously completely new to Vue, and I'm probably missing something stupid here.
So what am I doing wrong and how do I get the parsed data into my DOM?
Don't use an arrow function for your data function. Arrow functions bind this to whatever context the function is declared in. You need to let Vue properly bind this to the instance it is creating. So use
data() {
return postInfo;
}
or if for some reason you need to be old school:
data: function () {
return postInfo;
}

Vue JS v-for not iterating over array

Hi guys I am using Vue JS to try and loop through my data. Here is my whole JS file:
var contentful = require('contentful');
var client = contentful.createClient({
space: 'HIDDEN',
accessToken: 'HIDDEN'
});
Vue.component('careers', {
template: '<div><div v-for="career in careerData">{{ fields.jobDescription }}</div></div>',
data: function() {
return {
careerData: []
}
},
created: function() {
this.fetchData();
},
methods: {
fetchData: function() {
client.getEntries()
.then(function (entries) {
// log the title for all the entries that have it
entries.items.forEach(function (entry) {
if(entry.fields.jobTitle) {
this.careerData = entries.items;
}
})
});
}
}
});
var app = new Vue({
el: '#app'
});
I am using methods to access some data from Contentful, once it has grabbed the necessary data it is sent to my data object.
If I console.log(careerData); within my console the following data is returned:
So I'd expect if I used v-for within my template and tried iterating over careerData it would render correctly however on my front-end I am left with an empty div like so:
<div id="app"><div></div></div>
I am currently pulling my component into my HTML like so:
<div id="app">
<careers></careers>
</div>
No errors are displayed within my console, can you think of any reason this might be happening?
Thanks, Nick
Several problems I think. As #dfsq said, you should use a arrow function if you want to keep context (this).
fetchData: function() {
client.getEntries()
.then(entries => {
this.careerData = entries.items
});
}
Then you may replace {{fields.jobDescription}} by {{career.fields.jobDescription}}, as #unholysheep wrote.
It may work. If it does not, you could add a this.$forceUpdate(); right after this.fetchData();
Use arrow function in forEach callback so you don't loose context:
fetchData: function() {
client.getEntries()
.then(entries => {
this.careerData = entries.items
});
}

Categories