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
Related
I'm trying to implement Laravel's authorization & policy in Vue, by implementing a mixin which sends a GET request to a controller in the backend.
The problem is the v-if directive is receiving a Promise, which obviously does not resolve
Below is a very simplified version of what I'm trying to do:
The global mixin, auth.js
import axios from "axios"
export default {
methods: {
async $can (permission, $model_id) {
let isAuthorized = false;
await axios.get(`/authorization?${permission}&${model_id}`)
.then(function (response) {
isAuthorized = response.data.isAuthorized
})
.catch((error) => {
isAuthorized = false;
});
return isAuthorized;
}
}
}
The main entry file, app.js
import Auth from '#/auth';
Vue.mixin(Auth);
...
new Vue({...})
Component.vue
<template>
<div>
<div v-if="$can('do-this', 12)">
Show Me
</div>
</div>
</template>
<script>
export default {}
</script>
Is there any way to 'await' the async $can operation in v-if? Or am I approaching this from a totally wrong direction?
You don't need async/await there because axios returns a promise. I think you can call that function from the created hook. Instead of returning a value, change the related data attribute, and use it in v-if like so:
<div v-if="permissions['do-this__12']">
data() {
return {
permissions: {
'do-this__12': false,
'or-this__13': false,
},
}
}
methods: {
getPermissions() {
for (const key in this.permissions) {
this.can(key.split('__')[0], key.split('__')[1])
}
},
can(permission, model_id) {
axios.get(`/authorization?${permission}&${model_id}`)
.then(response => {
this.permissions[`${permission}__${model_id}`] = response.data.isAuthorized
})
.catch(error => {
this.permissions[`${permission}__${model_id}`] = false;
});
},
}
created() {
this.getPermissions();
}
I didn't try my code, let me know if it fails. BTW, extracting this implementation to a mixin will be a better idea. If you like to do that, just leave "permissions" object in the component and move everything else to the mixin.
But that approach isn't effective when you need multiple API calls for permissions. That's why I think you should pass the whole permissions object to the backend and make the work in the server:
iPreferThisBecauseOfSingleAPICall() {
axios.get(`/authorization`, this.permissions)
.then(({ data }) => this.permissions = data)
}
// AuthorizationController
public function index(Request, $request)
{
$permissions = [];
foreach($request->all() as $permission) {
// run your backend code here
}
return $permissions;
}
One final note, instead of asking for permission each time, loading all permissions at one can be the best idea.
im really going through hard times trying to figure out how to get my API data through Vuex, is there some body whom has accurate bibliography of how to do this step by step, or even better help me with this code?
Formerly without using Vuex , but Vue all request worked perfectly, but now i dont understand clearly what i should do, here sharing part of my code:
data() {
return {
testArray: []
};
methods: {
getJsonData() {
fetch(
"https://app.ticketmaster.com/discovery/v2/events.json?countryCode=" +
this.countriesDrop +
"&apikey=xxxxxxxxxxxxxxxxxxxxxxxx",
{
method: "GET"
}
)
.then(response => {
return response.json();
})
.then(test => {console.log(this.testArray)
this.testArray = test._embedded.events;
})
.catch(err => {
console.log(err);
});
},
watch: {
countriesDrop: function(val) {
this.getJsonData();
}
},
As you can see in the request also is included an external element which make it changes attuning with the watcher and the value the user might asign.
I already got set Vuex and all else pluggins...just dont know how to act like , thus would appreciate an accurate link or tutorial either help with this basic problem resolved on detail step by step, .....thanks!
In your code there's nothing with Vuex. I guessed you want to set the state so that the getJsonData() method is called according to what's in the store.
Here's a snippet as an example of handling async in a Vuex environment.
const store = new Vuex.Store({
state: {
testArray: []
},
mutations: {
setTestArray(state, data) {
state.testArray = data
}
},
actions: {
getJsonData({
commit
}, countriesDrop) {
if (countriesDrop && countriesDrop !== '') {
fetch(`https://jsonplaceholder.typicode.com/${countriesDrop}`, {
method: "GET"
})
.then(response => {
return response.json();
})
.then(json => {
commit('setTestArray', json)
})
.catch(err => {
console.log(err);
});
}
}
}
})
new Vue({
el: "#app",
store,
computed: {
getDataFromStore() {
return this.$store.state.testArray
}
},
methods: {
getData(countriesDrop) {
this.$store.dispatch('getJsonData', countriesDrop)
}
}
})
<script src="https://cdn.jsdelivr.net/npm/es6-promise#4/dist/es6-promise.auto.js"></script>
<script src="https://unpkg.com/vuex#3.1.2/dist/vuex.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<button #click="getData('todos')">GET TODOS</button>
<button #click="getData('albums')">GET ALBUMS</button>
<ol>
<li v-for="data in getDataFromStore">{{data.title}}</li>
</ol>
</div>
The point is that Vuex is a central element in a Vue-Vuex application. You can store app state, handle async and sync functions (actions, mutations) with it, and all your Vue components can rely on the state - that should be the "single source of truth".
So, you get your input from a component (the Vue instance in this snippet), and dispatch an action that is available in the Vuex store. If the action needs to modify the state, then you call a mutation to do that. With this flow you keep reactivity for all your components that use that state.
I used a computed to get data from the Vuex store, but getters can be set also.
This way you don't "pollute" your components with functions and data that should be in the store.
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.
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.
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();
},