Vue JS v-for not iterating over array - javascript

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
});
}

Related

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;
}

How to send data to component in vue js?

How do I send data to a component in Vue.js? I got a response from the server on the button click event, and now I want to send this response to the component and display on list using v-for.
Here is my code:
var store = new Vuex.Store({
state: {
Item: []
},
mutations: {
getItems: function (state) {
}
},
actions: {
fetchData:function (context) {
Vue.http.get('data.json').then(function(response){
alert('dd')
}, function(error){
console.log(error.statusText);
});
}
}
})
var httprequest = Vue.extend({
"template": '#http_template',
data: function () {
return {
items: store.state.Item
}
},
methods: {
fetchData: function () {
store.dispatch('fetchData')
},
}
})
Vue.component('httprequest', httprequest);
var app = new Vue({
el: '#App',
data: {},
});
You have almost done everything correct. Only thing you are missing is after getting data, you are not assigning it to state.Item. Please check the below code:
var store = new Vuex.Store({
state: {
Item: []
},
mutations: {
getItems: function(state, items) {
items.forEach(function(item) {
state.Item.push(item)
})
}
},
actions: {
fetchData: function(context) {
Vue.http.get('data.json').then(function(response) {
context.commit('getItems', response.data)
}, function(error) {
console.log(error.statusText);
});
}
}
})
working example can be found here.
You don't send data to components. You set up reactive pipes and the data moves around when it needs to. In your case, with vuex, you want to register store.state.items on the data of your component.
You can use a prop if you want, but you still need to do the registration in the parent's data. If your component is a singleton, intended for this page only, you're better registering what you need directly in the data of the component.
In general vue follows the principle that data goes the DOM tree down via properties and up via events. See for example https://v2.vuejs.org/v2/guide/index.html#Composing-with-Components.
Thus to get data into your component define a property myProp inside your component and when using your component bind it via v-bind:myProp="myData".
To get data back from your component use this.$emit('myUpdateEvent', myUpdatedData) and listen to the event by using v-on:myUpdateEvent="myUpdateHandler".

vue.js render ajax data that contains vue.js syntax

Vue.js version is: 2.x
Hi. I'm sending an ajax request in vue js to another page and getting it's source which contains vue.js syntax such as events. When this source is added to property and property added to a template, the ajax data source (that contains vue.js syntax) can not be rendered and does not work properly.
For example template is:
<div id="app">
{{{ foo }}}
</div>
and app.js is:
var app = new Vue({
el: '#app',
data: {
foo: 'bar'
},
mounted(){
this.$http.get('/media').then(function(response){
data = response.body;
Vue.set(app, 'foo', data);
});
},
methods: {
alertVideoLink: function(event){
alert(event.target.href);
}
}
});
In the above app.js code, ajax request returns this code (that is response.body):
Video Link
but this link can't be rendered and does not work properly! I'm testing the render method and some useful hints, but no way found. Please help... Thanks
Sounds like you want to use an Async Component.
Something like...
components: {
'async-media': () => Vue.http.get('/media').then(res => ({
template: res.body,
methods: {
alertVideoLink (event) {
this.$emit('click', event)
}
}
}))
}
Then in your template...
<async-media #click="handleClickEventFromChildComponent" />
Here's an example using a timeout to fake "load" a template
var app = new Vue({
el: '#app',
data: {},
components: {
'async-media': () => new Promise(resolve => {
setTimeout(() => {
resolve({
template: 'Video Link',
methods: {
alertVideoLink(event) {
this.$emit('click', event.target.href)
}
}
})
}, 2000)
})
},
methods: {
handleClickEventFromChildComponent (href) {
console.info('Clicked on', href)
}
}
});
<div id="app">
<p>Wait 2 seconds</p>
<async-media #click="handleClickEventFromChildComponent" />
</div>
<script src="https://unpkg.com/vue#2.4.2/dist/vue.min.js"></script>
#Phil's answer is correct but in my project need to be changed. in this case, the better way is: using global components vs local components because is simple for this work.

vuejs v2.0 pass data to component

I built an app on Laravel 5.3 using vue.js and im starting to move over to vue.js to make the pages dynamic. I got everything working on a single page so want to convert that over to a component but after doing so I get the following error:
[Vue warn]: Error when rendering component <homepage> at C:\xampp\htdocs\.......
TypeError: Cannot read property 'nxt_weekly' of undefined
I was passing data to the view like so:
const app = new Vue({
el: '#app',
mounted: function () {
this.fetchEvents();
},
data: {
loading: true,
stats: []
},
methods: {
fetchEvents: function () {
this.$http.get('home/data').then(function (response) {
this.stats = response.body;
this.loading = false;
}, function (error) {
console.log(error);
});
}
});
In stats[] is where I hold the JSON response from the API and then call them all in my view like so:
<span class="stat" v-text="'stats.nxt_today'"></span>
....
....
This works but when I switch over to creating a component the errors listed above show, my new code is:
Vue.component('homepage', require('./components/Homepage.vue'),{
mounted: function () {
this.fetchEvents();
},
data: function () {
return{
loading: true,
stats: []
}
},
methods: {
fetchEvents: function () {
console.log('running here');
this.$http.get('home/data').then(function (response) {
this.stats = response.body;
this.loading = false;
}, function (error) {
console.log(error);
});
}
}
});
What am I doing wrong? How come my stats[] object is now empty when the component is trying to access it?
You need to pass your stats as a property to the component using v-bind, as shown below:
<homepage v-bind:stats="stats"></homepage>
The above needs to be done in your root template. And in your homepage component, you can receive the value in props as follows:
Vue.component('homepage', {
props: ["stats"],
mounted: function () {
// ...
},
// ...
}
Within the template of this component, you will be able to access stats.nxt_today normally.
By the way, is your stats an array or an object? You have defined it as an empty array initially, but accessing it as an object.
If you still have issues, you can use vue-devtools to view all the objects available within a component.

React Component JSON Callback Scope

I'm using generator-react-webpack to create a React web app. This web app relies on JSON feeds - one of which is hosted on a CDN that does not support JSONP and the CDN url is a subdomain of the webapp. Is there any way to return the JSON data from within the React Component?
Basic React Component:
var AppComponent = React.createClass({
loadData: function() {
jQuery.getJSON(jsonFile.json?callback=?)
.done(function(data) {
console.log(data);
}.bind(this));
},
render: function(){
return ( ... );
}
});
I've tried a few solutions, and have come to the conclusion that I need to define my own callback on the JSON file like so:
JSON:
handleData({
"data": "hello World"
})
Is there a way for the handleData callback to be defined in the react component, or the response accessed from the react component? Any thoughts as to how I can get this to work are much appreciated. Thanks!
This looks like an odd way to do things, especially the part where you're using jQuery. That's a client-side utility to overcome not knowing where everything is and not having direct access to your elements. It makes no sense to use it when you're using React weith Webpack for bundling: React already knows where everything is (using refs) and Webpack means you can just use regular universal Node modules for everything that you need to do.
I'd recommend using something like, using request or a similar universal fetch API:
// loadData.js
var request = require('request');
var loadData = function(urlYouNeed, handler) {
request(urlYouNeed, function(error, response, body) {
if (error) {
return handler(error, false);
}
// do anything processing you need on the body,
var data = process(body);
handler(false, data);
};
So: just a module you can require in any component you define with require('./loadData'). And then in your actual component you do this:
var loadData = require('./loadData');
var AppComponent = React.createClass({
getDefaultProps: function() {
return {
jsonURL: "cdn://whateverjson.json"
};
},
getInitialState: function() {
loadData(this.props.jsonURL, this.updateData);
return {
data: []
}
},
updateData: function(err, data) {
if (err) {
return console.error(err);
}
data = secondaryEnsureRightFormat(data);
this.setState({ data: data });
},
render: function(){
var actualThings = this.state.data.map((entry, pos) => {
return <Whatever content={entry} key={entry.dontUseThePosVariableUpThere}/>
});
return (
<div>
...
{actualThings}
...
</div>
);
}
});
Much cleaner.
If I understand correctly the question, you only have to change your loadData this way :
loadData: function() {
var c = this
jQuery.getJSON(jsonFile.json?callback=?)
.done(function(data) {
c.handleData(data)
});
},
handleData: function(data) {
/* Implement here the function to handle the data */
},

Categories