this.$http.get is not working inside methods vue js - vuejs2

I am working with Laravel + spark + vue js.
Blade file
<draggable class="col-md-12" :list="emergencies" :element="draggableOuterContainer" #end="onEnd">
Js file
import draggable from 'vuedraggable'
module.exports = {
data() {
return {
emergencies:[]
};
},
components: {
draggable,
},
created() {
this.getEmergencies();
},
methods: {
getEmergencies() {
this.$http.get('/ajax-call-url')
.then(response => {
this.emergencies = response.data;
});
},
onEnd: function(evt){
var counter = 1;
this.emergencies.forEach(function(user, index) {
this.$http.get('/ajax-call-url/')
.then(response => {
});
counter++;
});
}
}
};
Here I have drag and Drop, On Drop, I call "onEnd" function and getting following error.
TypeError: this is undefined
Here this.emergencies.forEach is working but it is giving error on this.$http.get
Any suggestions, what can be the solutions?

Instead of using function syntax, use arrow functions, as scope of this changes inside function:
onEnd: function(evt){
var counter = 1;
this.emergencies.forEach((user, index) => {
this.$http.get('/ajax-call-url/')
.then(response => {
});
counter++;
});
}
Check this for explanation.

Related

Cannot access $refs inside mounted function VUE

In my template I have:
<apex-chart v-if="followers_options" ref="chart1" height="160" type="area" :options="followers_options"
:series="followers_series"></apex-chart>
I'm calling this function on mounted:
export default {
components: {
app: appLayout,
auth: authLayout,
},
mounted: function () {
this.uChart()
},
methods: {
uChart: function() {
const store = useStore();
let weight_series = [];
store
.dispatch("getWeights")
.then((data) => {
for (var j = 0; j < data.table.length; j++){
weight_series.push(data.table[j].weight);
}
console.log(this.$refs.chart1);
this.$refs.chart1.updateSeries([{ name: 'Weight', data: weight_series }]);
})
.catch((error) => {
console.log(error);
});
}
}
};
Yet when I look at the console I get undefined on the $refs log and couldn't find updateSeries on the other line.
I've also tried with a plain input tag with a ref but had no luck.
I'm new to vue so any help would be greatly appreciated.
cheers
To see the $ref yet it was undefined.

vuejs not setting data property from arrow function

I got this weird thing going on here:
I have this data property in vue
data() {
return {
currentLat: 'intial Lat',
currentLong: 'intial Long',
};
},
mounted() {
this.getCurrentLocation();
},
methods: {
getCurrentLocation() {
navigator.geolocation.getCurrentPosition((position) => {
this.currentLat = position.coords.latitude;
this.currentLong = position.coords.longitude;.
console.log(this.currentLat); this prints 41.2111
});
console.log(this.currentLat); this prints 'intial Lat'
},
},
this.currentLat not set in the mount
I dont understand what's happing here! it's so weird!
Here is an example of converting to a promise and using async/await:
async getCurrentLocation() {
const position = await new Promise(resolve => {
navigator.geolocation.getCurrentPosition(position => resolve(position))
});
this.currentLat = position.coords.latitude;
this.currentLong = position.coords.longitude;
console.log(this.currentLat); // shouldn't print initial value
},
Your code is valid, the callback arrow function is asynchronous (it's not executed immediately) and the call of console.log(this.currentLat); is synchronous which makes it to be executed before the callback context, the property is properly if you use it inside the template it will work fine
Set the values in a callback as follows:
<template>
<div id="app">{{ currentLat }} - {{ currentLong }}</div>
</template>
<script>
export default {
data() {
return {
currentLat: "intial Lat",
currentLong: "intial Long",
};
},
mounted() {
this.getCurrentLocation();
},
methods: {
getCurrentLocation() {
navigator.geolocation.getCurrentPosition(this.setCoordinates);
},
setCoordinates(position) {
this.currentLat = position.coords.latitude;
this.currentLong = position.coords.longitude;
},
},
};
</script>

How to access Vue $refs in a plugin?

methods: {
async create () {
this.disableSubmit = true;
await this.$firestore
.collection('collectionName')
.add(this.item)
.then(() => {
this.$refs.createForm.reset();
this.$notify('positive', 'Item successfully created!');
})
.catch(error => {
this.$notify('negative', 'ERROR! Try again later!', error);
});
this.disableSubmit = false;
},
}
If I use the code above inside the methods property, then everything works fine, but I would like to access that ref from outside the Vue component, for example a plugin, but it gives me an error.
TypeError: "_this.$refs is undefined"
Even when I just import it as a function, the error is the same, so I would like to know how to access the ref outside vue?
Bellow is the code for my plugin, and I would also like to point that I am using the quasar framework.
export let plugin = {
install (Vue, options) {
Vue.prototype.$plugin = async (collection, item) => {
return await firestore
.collection(collection)
.add(item)
.then(() => {
this.$refs.createFrom.reset();
notify('positive', 'Booking successfully created!');
})
.catch(error => {
notify('negative', 'ERROR creating booking! Try again later!', error);
});
};
}
};
I hope my question makes sense, and thanks in advance for any help
you could pass the context of your component, to apply the reset form from your plugin:
// plugin declaration
Vue.prototype.$plugin = async (collection, item, ctx) {
...
ctx.$refs.createFrom.reset()
...
}
then when u call to your plugin from yours components can do it like this:
// your component
methods: {
myFunction () {
this.$plugin(collection, item, this)
}
}
this is the reference of the context of your current component that will be used inside of your plugin
for example:
Vue.component('my-form', {
methods: {
resetForm() {
console.log('the form has been reset')
}
}
})
Vue.prototype.$plugin = (item, ctx) => {
console.log('item passed:', item)
ctx.$refs.refToMyForm.resetForm()
}
new Vue({
el: '#app',
data: {
item: 'foo'
},
methods: {
submit() {
this.$plugin(this.item, this)
}
}
})
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<div id="app">
<my-form ref="refToMyForm"></my-form>
<button #click="submit">submit</button>
</div>

use vanilla-lazyload with vuejs

I'm pretty new in Vue-js and I'm trying to use this.
My App is not a SPA and I'm also working with Laravel.
I've tried this and it works fine:
const app = new Vue({
el: '#app',
mounted() {
this.myLazyLoad = new LazyLoad({
elements_selector: '.lazy',
class_loaded: 'lazy-loaded',
load_delay: 500, //adjust according to use case
threshold: 100, //adjust according to use case,
callback_enter: function(el) {
console.log(el.getAttribute("data-src"));
}
});
}
});
<img data-src="{{ $featuredItem->anime->getPortraitImg()}}"
class="lazy img-fluid" src="/img/placeholder-anime.jpg">
But there is a problem when I try to use the lazyload in a Component.
For example:
export default {
mounted() {
console.log('Component mounted.');
console.log(Vue.prototype.LazyLoad);
this.myLazyLoad = new LazyLoad({
// elements_selector: '.lazyx',
container: document.getElementById('lazyContainer')
});
// myLazyLoad.loadAll();
},
data() {
return {
episodes: {},
currentPage: 2
}
},
methods: {
loadMoreEpisodes() {
let uri = '/api/v1/episodes?page=' + this.currentPage;
this.axios.get(uri).then(response => {
console.log(response.data.data);
if (this.episodes.length === undefined) {
this.episodes = response.data.data;
} else {
this.episodes = this.episodes.concat(response.data.data);
}
this.myLazyLoad.update();
this.myLazyLoad.loadAll();
});
}
}
}
The new data inserted by axios is not recognized by the lazyload plugin.
I'm using this.myLazyLoad.update(); as stated in the documentation, but I'm not able to get it to work. Any suggestions?
I think DOM is not updated when you call update() method. Can you try using $nextTick?
this.$nextTick(() => {
this.myLazyLoad.update()
})

VueJS: Setting data initially based on http response

So I have a template .vue file:
<template>
<div id="app">
<textarea v-model="input" :value="input" #input="update"></textarea>
<div v-html="compiledMarkdown"></div>
</div>
</template>
<script>
var markdown = require('markdown').markdown;
export default {
name: 'app',
data() {
return {
input: '# Some default data'
}
},
mounted: function () {
this.$nextTick(function () {
this.$http.get(window.location.pathname + '/data').then((response) => {
this.input = response.body.markdown;
}) })
},
computed: {
compiledMarkdown: function() {
this.$http.post(window.location.pathname, {
"html": markdown.toHTML(this.input)}).then(function() {
},function() {
});
return markdown.toHTML(this.input);
}
},
methods: {
update: function(e) {
this.input = e.target.value
}
}
}
</script>
In the mounted function I am trying to set input equal to the response of an HTTP request, but when you view this file this.input is still the same as it was initially declared. How can I change this.input inside the compiledMarkdown function to be this.input in the mounted function. What other approaches might I take?
You can not call a async method from a computed property, you can use method or watcher to run asynchronous code, from docs
This is most useful when you want to perform asynchronous or expensive operations in response to changing data.
You have to ran that relevant code when input changes, like following:
var app = new Vue({
el: '#app',
data: {
input: '# Some default data',
markdown : ''
},
methods: {
fetchSchoolData: function (schoolId) {
var url = this.buildApiUrl('/api/school-detail?schoolId=' + schoolId);
this.$http.get(url).then(response => {
this.schoolsListData = response.data;
}).catch(function (error) {
console.log(error);
});
},
},
mounted: function () {
this.$nextTick(function () {
this.$http.get(window.location.pathname + '/data').then((response) => {
this.input = response.body.markdown;
})
})
},
watch: {
// whenever input changes, this function will run
input: function (newInput) {
this.$http.post(window.location.pathname, {
"html": markdown.toHTML(this.input)}).then(function() {
},function() {
this.markdown = markdown.toHTML(this.input);
});
}
},
Have a look at my similar answer here.