I am having a bear of a time getting my VueJs app to render data from an external API. I've attempted to search for a similar issue, but everything I've found has been of no help.
I'm using the the USDA's nutrition database. When I run the code below, I can see through dev tools that my getNutrients function is making a successful call to the database when I click the button, yet my v-for element won't render any data. If I attempt to simply render nutrients from my data object, I'm able to render all of the raw JSON, just not when I try to render singular items within the v-for element.
Any help with getting the render to work would be greatly appreciated.
Thank you in advance
<template>
<div>
<button #click="getNutrients">Click</button>
<ul>
<li v-for="nutrient in nutrients">{{nutrient.nutrient_id}}</li>
</ul>
</div>
</template>
<script>
import axios from 'axios'
export default {
name: 'home',
data () {
return {
nutrients: {}
}
},
methods: {
getNutrients: function () {
axios.get('https://api.nal.usda.gov/ndb/nutrients/?format=json&api_key=DEMO_KEY&nutrients=205&nutrients=204&nutrients=208&nutrients=269')
.then(response => {this.nutrients = response.data})
}
}
}
</script>
If it helps, I'm using the Vue Webpack template through the Vue-CLI.
The API's returning a report object, which contains an array of foods, each of which contains an array of nutrients, so you'd need to loop through the foods, then through the nutrients in each food:
<ul>
<li v-for="food in foods">
<h2>{{food.name}}</h2>
<ul>
<li v-for="nutrient in food.nutrients">{{nutrient.nutrient_id}}</li>
</ul>
</li>
</ul>
axios.get(url).then(response => {
this.foods = response.data.report.foods
})
Related
New to Vue and JS. I have a vue page myLists which takes an array of lists (containing media IDs for a title) which I used to make axios API calls and build a carousel (using vue3-carousel package) in the child with the return data sent as a prop. I'm currently dealing with a "Maximum recursive updates exceeded in v-for component " warning that I believe has to do with how I make my API calls. Here is the relevant code below:
Parent "myLists", has multiple lists (each list has movies) and fetches data from api using axios:
<template>
<div v-if="isReady">
<List v-for="list of theList" :key="list.id" :aList="list"></List>
</div>
</template>
export default {
setup() {
const theList = ref([]);
for (var myList of myLists) {
const aList = ref([]);
for (var ids of myList) {
var apiLink = partLink + ids;
axios.get(apiLink).then((response) => {
aList.value.push({
title: response.data.original_title || response.data.name,
overview: response.data.overview,
url: "https://image.tmdb.org/t/p/w500" + response.data.poster_path,
year: response.data.first_air_date || response.data.release_date,
type: ids[1],
id: response.data.id,
});
});
}
theList.value.push(aList.value);
}
return { theList };
},
computed: {
isReady() {
//make sure all lists are loaded from the api before rendering
return this.theList.length == myLists.length;
},
},
Child component "List" (not including script tag as I don't think it's too relevant) takes the fetched data as a prop and builds a carousel with it:
<template>
<Carousel :itemsToShow="4.5" :wrapAround="true" :breakpoints="breakpoints">
<Slide v-for="slide of aList" :key="slide">
<img
#click="showDetails"
class="carousel__item"
:src="slide.url"
alt="link not working"
:id="slide"
/>
</Slide>
<template #addons>
<Navigation />
<Pagination />
</template>
</Carousel>
</template>
Don't know what's causing the error exactly. I have a feeling it could be how I do all my API calls, or maybe it's something else obvious. Anyone have a clue?
The fix was actually absurdly simple, I was on the right track. The component was trying to render before my data was ready, so simply adding a
"v-if="list.length!==0"
directly on my Carousel component (within my List component), as opposed to the parent, fixed my issue.
I assumed that props are automatically ready when passed to a child if I used a v-if in my parent, turns out I was wrong, and that there's a delay.
Found the solution on the github issues page:
https://github.com/ismail9k/vue3-carousel/issues/154
I want to print the data in the inputs in the image to the screen via node js, how can I do this?
You could use a combination of an Array and an v-for statement
Basically:
//The UI
<ul>
<li v-for="(item, key) in array" v-bind:key="key">
//Here you can use now every item in the Array like this for example
<span>{{ item.name }}</span>
</li>
</ul>
//The code
export default {
data() {
return { array: [] };
},
methods: {
apiDataFunction() {
axios
.post('xxx') //Or whatever you have
.then((res) => {
this.array.push(res.data);
});
}
}
};
If you could give some more information I could help more.
For example, how the data looks that you retrieve with axios etc.
I didn't test this code personally so it may be, that you would need to pack this array into an computed statement
could it be that Inertia.js page components are blocking the reactivity of vue?
I have a Page component, in this component is a normal single file component.
I have a function that adds items to the ItemsManager.items object.
When I'm running this function the single component below doesnt adds this items in the v-for.
But when I'm reload the Page Component it works and the previously added items appear.
Here the single file component:
<template>
<div>
<div v-for="item in items" :key="item.$key">
test
</div>
</div>
</template>
<script>
import { ItemsManager } from "./utils.js";
export default {
name: "test-component",
data: () => ({
items: ItemsManager.items
}),
};
</script>
utils.js:
export const ItemsManager = {
items: [],
add(item) {
item.$key = this.items.length;
this.items.unshift(item);
},
};
function that adds the items (in page component):
addItem(title, options) {
ItemsManager.add({
name: title,
options: options
});
},
Thanks in advance!
Since you're using Vue2, you need to know that there are some caveats when adding/deleting things to Objects/Arrays. You don't show any code relevant to your actual way of adding stuff to your object, but I can still recommend that you'd check this page to understand and fix your issue.
https://v2.vuejs.org/v2/guide/reactivity.html#Change-Detection-Caveats
I am using vuex to save a tree structure in the state property.
The data is fetched with an ajax call.
The problem is that the page manages to render before the variable I have in the state property manages to populate.
i.e
// sth.ts file
state: {
map: {}
},
...
actions: {
getData({ commit }){
axios.get(...).then(... populate map ...).catch(...)
}
}
// sthelse.vue file
<template>
<div>
<h1>Tree structure</h1>
<ul >
<item v-for="child in map[root]"
:key="child.id"
:name="child.name"
:children="child.Children">
</item>
</ul>
</div>
</template>
I have googled but I haven't found something that works.
Has anybody dealt with a similar problem?
Is there a way it can be done?
Store a reference to the loaded map keys inside the vuex state like:
state: {
map: {},
keysLoaded: []
}
Then inside the mutation that handle the data push the key to keysLoaded, the in your component you can use a computed property like:
showTree () {
return this.$store.state.keysLoaded.includes(this.root)
}
render the ul only if showTree its true:
<ul v-if="showTree">
I must say first that I come from mobile development. I am very new with web development so this is probably an amateur questions.
I am building a react.js project using create-react-app (which uses Babel). I am trying to follow a tutorial where I am supposed to import a *.json file when my component mounts. I can't seem to be able to access my data, and I get an error saying "filteredApts.map is not a function".
Here are my imports:
import React from 'react';
import './App.css';
import $ from 'jquery';
Here is my componentWillMount method:
componentDidMount: function() {
console.log($.get('./data.json', function(){}.bind(this))) //This seems to get an HTML Page returned!
this.serverRequest = $.get('./data.json', function(result) {
var tempApts = result;
this.setState({
myAppointments: tempApts
}); //setState
}.bind(this));
},
my render method:
render: function() {
var filteredApts = this.state.myAppointments;
filteredApts = filteredApts.map(function(item, index) {
return (<li className="pet-item media" key={index}>
<div className="pet-info media-body">
<div className="pet-head">
<span className="pet-name">{this.state.myAppointments[index].petName}</span>
<span className="apt-date pull right">{this.state.myAppointments[index].petName}</span>
</div>
<div className="owner-name"><span className="label-item">Owner:</span>
{this.state.myAppointments[index].ownerName}</div>
<div className="apt-notes">
{this.state.myAppointments[index].aptNotes}</div>
</div>
</li>)
}.bind(this));
return (<div className="interface">
<div className="item-list media-list">
<ul className="item-list media-list"></ul>
</div>
</div>)
} //render
}); //MainInterface
Here is my map of files:
And finally my console log:
Is somebody capable of pointing out what I might be doing wrong?
I'd suggest to change this line:
var filteredApts = this.state.myAppointments;
to this
var filteredApts = this.state.myAppointments || [];
You use asynchronous data fetching and at the moment of rendering it can be no myAppointments yet.
Looks like your responseText is html.
I figured it out.
First, './data.json' was pointing to the public folder by default.
Second, I was missing {filteredApts} in
return (<div className="interface">
<ul className="item-list media-list">{filteredApts}</ul>
</div>)
Thanks anyways to all.