How do I fetch data once a component has been mounted? I start my vue instance and then load in the component, the component template loads in fine but the function calls in mounted are never run so the stats object remains empty, in turn, causing errors in the component/template that requires the data.
So how do I run a certain function on component load?
For what its worth... the functions I want to call will all make REST requests but each component will be running different requests.
Vue.component('homepage', require('./components/Homepage.vue'), {
props: ["stats"],
mounted: function() {
this.fetchEvents();
console.log('afterwards');
},
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);
});
}
}
});
const vue = new Vue({
el: '#main',
mounted: function() {
console.log('main mounted');
}
});
You are already doing it fine by putting all the initialization stuff into mounted. The reason your component is not refreshing is probably because of binding of this, as explained below:
In your fetchEvents function, your $http success handler provides a response, which you are attempting to assign to this.stats. But it fails because this points to that anonymous function scope and not to Vue component.
To overcome this issue, you may use arrow functions as shown below:
fetchEvents: function() {
this.$http.get('home/data').then(response => {
this.stats = response.body;
this.loading = false;
}, error => {
console.log(error);
});
}
Arrow functions do not create its own scope or this inside. If you use this inside the arrow function as shown above, it still points to Vue component, and therefore your component will have its data updated.
Note: Even the error handler needs to use arrow function, so that you may use this (of Vue component) for any error logging.
Related
There is such a code:
<template>
<div class="wrapper">
</div>
</template>
<script>
import axios from 'axios';
export default{
created () {
console.log('222');
this.getTrackerIdData();
this.getTrackerData();
},
methods: {
getTrackerIdData () {
return axios.get("https://seo-gmbh.eu/couriertracker/json/couriertracker_api.php?action=tracking_new.create" , {
})
.then(response => {
this.$store.commit('tracker/setTrackingKeyId', response.data.data.tracking_new_key_id);
this.$store.commit('tracker/setQrCodeUrl', response.data.data.filename_qr_code_tracking_new);
})
.catch(function (error) {
console.log(error);
});
},
getTrackerData () {
setInterval(()=>myTimer(this), 60000);
function myTimer(th) {
return axios.get("https://seo-gmbh.eu/couriertracker/json/couriertracker_api.php?action=get_tracking_data&key_id=" + th.$store.state.tracker.trackingKeyId , {
})
.then(response => {
th.$store.commit('tracker/setTrackingServerData', response.data.data.tracking_data);
})
.catch(function (error) {
console.log(error);
});
}
},
}
}
</script>
When starting such a solution in the project, the server-side developer informed me that at least the request method getTrackerIdData () on its side works twice!
Having placed the code (console.log ('222');) in the hook of the created lifecycle (where the method calls), I found that it is displayed twice in the firebug:
Question:
Why is this happening and what approach is right in this case from the point of view of the implementation of receiving data from the server?
P.S. If everything is called in the mounted hook, then the code works, including on the server side, only 1 time.
It is important to know that in any Vue instance lifecycle, only beforeCreate and created hooks are called both from client-side and server-side. All other hooks are called only from the client-side.
so thats why created hook called 2 times and executing the console.log ('222'); twice
for reference you can read from here
I am trying to create a web app based on a database. Setup: NodeJS and a Vuejs 2 app generated with the CLI (with Webpack). Currently, I am using axios to retrieve records into an object. Based on that object I want to draw some svg lines from certain points to other points. The method works completely as designed when running it from an #click (v-on directive). However, when I try to add it to the created hook it doesn't work. No errors displayed. It's just not running. Does anyone no why? Code example below.
<template>
<div class="holder">
<step v-for="item in steps"></step>
<events v-for="point in points"></events>
<button #click= "createArrows">Test</button>
</div>
</template>
<script>
import axios from 'axios'
import Step from './Step.vue'
import Events from './Events.vue'
export default {
name: 'Graph',
data () {
return {
steps: '',
events: '',
points: []
},
components: {
Step, Events
},
methods: {
getSteps: function() {
let getsteps = this
axios.get('localhost:8000/api/steps')
.then(function (response) {
getsteps.steps = response.data
})
.catch(function (error) {
getsteps.steps = "Invalid request"
})
},
getEvents: function() {
let getevents = this
axios.get('localhost:8000/api/events')
.then(function (response) {
getevents.events = response.data
})
.catch(function (error) {
getevents.events = "Invalid request"
})
},
createArrows: function() {
},
created() {
this.getSteps(),
this.getEvents(),
this.createArrows()
}
}
EDIT: Promises are already included in the axios library. Since I am new to this concept I missed this one. Refactored code below:
methods: {
getData: function() {
let getdata = this
axios.all([
axios.get('localhost:8000/api/steps'),
axios.get('localhost:8000/api/events')
])
.then(axios.spread(function (stepResponse, eventResponse) {
console.log('success')
getdata.steps = stepResponse.data
getdata.events = eventResponse.data
getdata.createArrows()
}))
.catch(function (error) {
console.log("Invalid request")
})
},
createArrows: function() {
}
},
created() {
this.getData()
}
}
</script>
I think it's a classic async issue.
With v-on, your call to createArrows is "timewise after" getSteps and getEvents: meaning that getSteps and getEvents have finished executing their internal ajax promises, have populated the relevant data into the component instance for createArrows to find and access.
However, inside the created() hook, if you think about it, the calls fall through to createArrows() instantaneously (before the promisy things inside getSteps and getEvents have finished).
You'll have to refactor the call to createArrows inside created() as promise resolve for it work there correctly.
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.
I have a function that helps filter data. I am using v-on:change when a user changes the selection but I also need the function to be called even before the user selects the data. I have done the same with AngularJS previously using ng-init but I understand that there is no such a directive in vue.js
This is my function:
getUnits: function () {
var input = {block: this.block, floor: this.floor, unit_type: this.unit_type, status: this.status};
this.$http.post('/admin/units', input).then(function (response) {
console.log(response.data);
this.units = response.data;
}, function (response) {
console.log(response)
});
}
In the blade file I use blade forms to perform the filters:
<div class="large-2 columns">
{!! Form::select('floor', $floors,null, ['class'=>'form-control', 'placeholder'=>'All Floors', 'v-model'=>'floor', 'v-on:change'=>'getUnits()' ]) !!}
</div>
<div class="large-3 columns">
{!! Form::select('unit_type', $unit_types,null, ['class'=>'form-control', 'placeholder'=>'All Unit Types', 'v-model'=>'unit_type', 'v-on:change'=>'getUnits()' ]) !!}
</div>
This works fine when I select a specific item. Then if I click on all lets say all floors, it works. What I need is when the page is loaded, it calls the getUnits method which will perform the $http.post with empty input. In the backend I have handled the request in a way that if the input is empty it will give all the data.
How can I do this in vuejs2?
My Code: http://jsfiddle.net/q83bnLrx
You can call this function in the beforeMount section of a Vue component: like following:
// .....
methods: {
getUnits: function() { /* ... */ }
},
beforeMount() {
this.getUnits()
},
// ......
Working fiddle: https://jsfiddle.net/q83bnLrx/1/
There are different lifecycle hooks Vue provide:
I have listed few are :
beforeCreate: Called synchronously after the instance has just been initialized, before data observation and event/watcher setup.
created: Called synchronously after the instance is created. At this stage, the instance has finished processing the options which means the following have been set up: data observation, computed properties, methods, watch/event callbacks. However, the mounting phase has not been started, and the $el property will not be available yet.
beforeMount: Called right before the mounting begins: the render function is about to be called for the first time.
mounted: Called after the instance has just been mounted where el is replaced by the newly created vm.$el.
beforeUpdate: Called when the data changes, before the virtual DOM is re-rendered and patched.
updated: Called after a data change causes the virtual DOM to be re-rendered and patched.
You can have a look at complete list here.
You can choose which hook is most suitable to you and hook it to call you function like the sample code provided above.
You need to do something like this (If you want to call the method on page load):
new Vue({
// ...
methods:{
getUnits: function() {...}
},
created: function(){
this.getUnits()
}
});
you can also do this using mounted
https://v2.vuejs.org/v2/guide/migration.html#ready-replaced
....
methods:{
getUnits: function() {...}
},
mounted: function(){
this.$nextTick(this.getUnits)
}
....
Beware that when the mounted event is fired on a component, not all Vue components are replaced yet, so the DOM may not be final yet.
To really simulate the DOM onload event, i.e. to fire after the DOM is ready but before the page is drawn, use vm.$nextTick from inside mounted:
mounted: function () {
this.$nextTick(function () {
// Will be executed when the DOM is ready
})
}
If you get data in array you can do like below. It's worked for me
<template>
{{ id }}
</template>
<script>
import axios from "axios";
export default {
name: 'HelloWorld',
data () {
return {
id: "",
}
},
mounted() {
axios({ method: "GET", "url": "https://localhost:42/api/getdata" }).then(result => {
console.log(result.data[0].LoginId);
this.id = result.data[0].LoginId;
}, error => {
console.error(error);
});
},
</script>
methods: {
methodName() {
fetch("url").then(async(response) => {
if (response.status === 200) {
const data = await response.json();
this.xy = data.data;
console.log("Success load");
}
})
}
}
you can do it using created() method. it will fire once page fully loaded.
created:function(){
this.fillEditForm();
},
I am starting with Vue.js and is really hard to find documentation about Unit Test.
I am trying to test components methods and builtin stuff as ready(). I can call those correctly but they internally have references to this object and this context is lost during testing time.
error
TypeError: this.$on is not a function
spec.js
import Vue from 'vue';
import Partners from 'components/main/partner/Partners';
describe.only('Partners.vue', () => {
it('should render with mocked partners', (cb) => {
Partners.ready(); // I get an error here because ready() is calling inside: this.$on(...)
cb(null);
});
});
component.vue
export default {
name: 'Partners',
data() {
return { };
},
methods: {
get() {
// ...
}
},
ready() {
this.$on('confirm', (confirm) => {
// ...
});
this.get();
}
};
I think ready() is depreciated along with Vue 1.0. Consider upgrading to Vue 2 (where mounted() replaces ready()).
To test your component, you need to initialize your component and a Vue instance, (and usually mount it, depending what you are doing).
Using the vue-webpack template (which uses Vue 2):
var ctor = Vue.extend(Partners)
var vm = new ctor()
vm.$mount()
now you can do things like vm.method(), and vm.mount() will automatically be called, etc.