How to send data to component in vue js? - javascript

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".

Related

Parent's data change does not update child component in vuejs

I have the following:
Vue.component('times-updated', {
template: '<span>Times Updated: {{ timesUpdated }}</span>',
data: function() {
return {
timesUpdated: this.$parent.myData.timesUpdated
}
}
});
var vm = new Vue({
el: '#test',
data: function() {
return {
myData: {}
}
}
})
setInterval(function(){
$.ajax({
url: `${window.location.href}/json`, // This just returns an array : array.timesUpdated: 2 etc
}).done(function (data) {
vm.myData = data; // changes this data
});
}, 1000)
and am using the following html:
<div class="test">
<times-updated></times-updated>
</div>
I poll a REST API that returns an array which includes a timesUpdated property:
{
timesUpdated: 5
}
My intention is that every second I use jQuery's $.ajax method to call the API, update the myData data object on vm, which would then update the times-updated component.
The code works on initial page load, the times-updated component can retrieve the value on its parent's myData property, but whilst I have confirms that vm.myData does reflect the new value from the API, the component doesn't update its display to show the new count.
What am i doing wrong?
The data function is only called once during the life cycle of the component; when it is initially created. So essentially your component is just displaying the value as it existed when the component was created.
Additionally, it's generally bad practice to reach out of a component to get a data value. Vue is props down, events up. You should convert your component to use a property.
Vue.component('times-updated', {
props:["times"],
template: '<span>Times Updated: {{ times }}</span>',
})
The fact that you are using a function to define the Vue in this particular case doesn't really matter, it's just not a typical practice. Components require a function because they need an isolated scope.
Here is an example.
That callback is required only in components
// vue instance
new Vue({
data: {
status: true
}
};
// vue components (callback)
Vue.component('custom-component', {
data: function() {
return {
status: false
}
}
});

How to get the latest data from parent to child components after page refresh

I am working on a project and using Vue.js for the frontend. I have following code in the main.js file.
new Vue({ // eslint-disable-line no-new
//el: '#app',
router,
data () {
return {
friends: []
}
},
methods: {
getFriends: function () {
return this.friends;
}
},
created: function () {
this.$http.get('/user/' + this.getUserIDCookie('userID') +
'/friends').then(function (response) {
this.friends = response.data;
});
},
components: {
'nav-bar': require('./components/Navigation.vue')
},
template: `
<div id="app">
<nav-bar></nav-bar>
<router-view class="router-view"></router-view>
</div>`
}).$mount('#app');
In one of the pages(for ex. when the page is redirected to localhost/#/user/1/details, I am retrieving the friends' list from main.js like below:
<script type="text/babel">
export default {
name: 'profile',
data: function () {
return {
user: {},
friends: []
}
},
methods: {
// Some methods
},
created: function () {
this.friends = this.$root.getFriends();
}
}
</script>
The problem arises when I refresh the current page. After page refresh, this.friends is null/undefined because this.$root.getFriends() is returning null/undefined. I can move it to user component, but I want to keep it in main.js so that GET call is used once and data will be available to the whole application.
Any input regarding how to solve this issue would be great. I am using Vue 2.0.1
Really, what you want to do, is pass the data the component needs as props.
The dirt simple easiest way to do it is this.
<router-view class="router-view" :friends="friends"></router-view>
And in your profile component,
export default {
props:["friends"],
name: 'profile',
data: function () {
return {
user: {},
friends: []
}
},
methods: {
// Some methods
}
}
If you want to get more sophisticated, the later versions of VueRouter allow you to pass properties to routes in several ways.
Finally, there's always Vuex or some other state management tool if your application gets complex enough.
The problem is that when you refresh the page, the whole app reloads, which includes the get, which is asynchronous. The router figures out that it needs to render details, so that component loads, and calls getFriends, but the asynchronous get hasn't finished.
You could work around this by saving and pulling the Promise from the get, but Bert's answer is correct: the Vue Way is to send data as props, not to have children pull it from parents.

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.

How to implement a function when a component is created in Vue?

According to the docs, the constructor of the Vue object is managed like this.
var vm = new Vue({
created: function () { console.log("I'm created!"); }
});
However, I can't figure out how to do the corresponding thing when a Vue component is created. I've tried the following but don't get any print to the console.
export default {
created: function() { console.log("Component created!"); }
}
Is it possible to subscribe/listen to a component being rendered? I'd like to react to that event by downloading some data and putting it in the store, so that the table that the component carries will get its information to display.
In my applications, I tend to use the mounted hook to load up some Ajax data once the component has mounted.
Example code from my app:
Vue.component('book-class', {
template: '#booking-template',
props: ['teacherid'],
data: function () {
return{
// few data items returned here..
message: ''
}
},
methods: {
// Few methods here..
},
computed: {
// few computed methods here...
},
mounted: function () {
var that = this;
$.ajax({
type: 'GET',
url: '/classinfo/' + this.teacherid,
success: function (data) {
console.log(JSON.stringify(data));
}
})
}
});
new Vue({
el: '#mainapp',
data: {
message: 'some message here..'
}
});
However, I can also use created() hook as well as it is in the lifecycle as well.
In Vue2 you have the following lifecycle hooks:
components doesn't have life cycle hooks like app. but they has something similar. that fixed my problem:
https://v2.vuejs.org/v2/api/#updated

How to access child component data in v-if outside of component?

In short, I want to get a value from a child component and check what it is in the parent. I have a working implementation using computed properties and a reference via v-ref on the child component, but I was wondering if I am doing it the right way and if there's a better/proper way to do it.
To get to specifics, I have a component with checkboxes, the checked checkboxes' values within this component are kept in the components data in an array variable named selected. Outside of the component I want to conditionally show a <div> using v-if however I'm unsure how to correctly grab the child component's selected value.
Here's a brief overview of my code:
component mark up
<student-table
v-ref:student-table
:data="students"
:course="course"
:columns="columns"
>
</student-table>
component registration
Vue.component('student-table', {
/* unrelated code */
data: function () {
return {
selected: []
}
},
/* unrelated code */
})
main vue instance
var vueApp = new Vue({
/* unrelated code */
computed: {
selected: function () {
return this.$refs.studentTable.selected.length
}
},
/* unrelated code */
})
Then in my html I can reference selected and I'll get the length of StudentTable.selected and thus be able to use it in my v-if
Thanks for any guidance or help!
Edit
I'm getting this in my console:
[Vue warn]: Error when evaluating expression "function () {
return this.$refs.studentTable.selected.length
}". Turn on debug mode to see stack trace.
There are several ways to share data between parents / components such as 2-way binding between parent/child and also sending and listening for events.
Here is an events example with $broadcast and $dispatch:
parent vue:
var parentVue = new Vue({
...
compiled: function(){
this.$on('receiveDataFromChild', function(){
//do something with the data from the child
});
},
methods: {
checkChildForData: function(){
this.$broadcast('pleaseSendDataToYourMama');
}
}
});
child vue:
var childVue = new Vue({
...
compiled: function(){
this.$on('pleaseSendDataToYourMama', function(){
this.$dispatch('receiveDataFromChild',this.someImportantData);
});
}
});
This is how I now have it working, I'm not sure this is the best way but I'm not getting any console.warn alerts in my console. Would love any feedback. Many thanks to #Douglas.Sesar
// child
Vue.component('student-table', {
parent: vueApp,
data: function () {
return {
selected: []
}
},
watch: {
selected: function() {
this.$dispatch('updateSelected', this.selected);
}
},
})
// parent
var vueApp = new Vue({
components: {
child: studentTable
},
data: {
selected: []
},
events: {
updateSelected: function(selected) {
this.selected = selected;
}
},
})

Categories