Vuejs ajax call not mapping changes to underlying html table - javascript

I am making simple ajax call with vuejs and axios:
var app1 = new Vue({
el: '#app1',
data: {
test: []
},
methods: {
setAJAX: function () {
axios.get('/Departments/GetDepartments/').then(response => this.test = response.data.listBACAET);
}
}
});
Why is this working:
setAJAX: function () {
axios.get('/Departments/GetDepartments/').then(response => this.test = response.data.listBACAET);
}
But this is not working, changes are not mapped into table (this.test is undefined):
setAJAX: function () {
axios.get('/Departments/GetDepartments/').then(function(response){this.test = response.data.listBACAET});
}

This is because of the way arrow functions work: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions#No_separate_this
When using an arrow function, this is implicitly bound to this of the enclosing scope, which is, in your case, the vue instance on which the method is called.
So you're setting the data of your view model, which works.
When using a std. function, there is no this in the scope, hence the error. To use a std. function, you need to define a closure for your view model like this:
setAJAX: function () {
let vm = this
axios.get('...').then( function(response) {
vm.test = response.data.listBACAET
});
}

Related

How to change the context of this inside object

I want to access a function which is outside my base object, but if we console.log(this) inside loadAll function then it will give the context inside object. If I console.log(this) any normal function i.e without action or getter/setters it will give context of whole class which I want to achieve
base = observable({
isDeleting: false,
registry: observable.map(),
get all() {
return this.registry.values();
},
loadAll:action.bound(function () {
console.log(this);
this.request()
}),
});
request = () => {
console.log('hello');
}
In The above example this will throw an error because it can't access the request function but I wan to find a way to access it.
base = observable({
isDeleting: false,
registry: observable.map(),
get all() {
return this.registry.values();
},
loadAll:action.bound(function () {
console.log(this);
this.request()
}),
request: () => {
console.log(this) //This will give context of all the function outside object that is what I want in above example.
console.log('hello');
},
});

Lodash's _.debounce() not working in Vue.js

I am trying to run a method called query() when a component property called q in Vue.js is modified.
This fails because this.query() is undefined. This is referring to my component's instance but somehow does not contain the methods.
Here's the relevant code part where I'm trying to watch the component property q and run the query() function:
methods: {
async query() {
const url = `https://example.com`;
const results = await axios({
url,
method: 'GET',
});
this.results = results.items;
},
debouncedQuery: _.debounce(() => { this.query(); }, 300),
},
watch: {
q() {
this.debouncedQuery();
},
},
Error:
TypeError: _this2.query is not a function
If I write the debounce() call as below, the TypeError: expected a function error appears even earlier, at the page load.
debouncedQuery: _.debounce(this.query, 300),
The issue comes from the lexical scope of the arrow function you define within _.debounce. this is bound to the object you are defining it in, not the instantiated Vue instance.
If you switch out your arrow function for a regular function the scope is bound correctly:
methods: {
// ...
debouncedQuery: _.debounce(function () { this.query(); }, 300)
}
We can do it by plain JS (ES6) with few lines of code:
function update() {
if(typeof window.LIT !== 'undefined') {
clearTimeout(window.LIT);
}
window.LIT = setTimeout(() => {
// do something...
}, 1000);
}
As answered in another post This is undefined in Vue, using debounce method the best way to add debouncing IMO is to create the method normally in methods as eg:
setHover() {
if (this.hoverStatus === 'entered') {
this.hoverStatus = 'active'
}
},
But then replace it in your created block eg:
created() {
this.setHover = debounce(this.setHover, 250)
},

Function call or definition inside object scope?

While going through VueJS sources I've come across this piece:
const injectedComp = {
inject: ['foo', 'bar'],
render () {},
created () {
injected = [this.foo, this.bar]
}
}
My question is - what are render () and created () - function calls? definitions? something else? What exactly is happening in there?
Both render and created are properties of the injectedComp object with function values. The syntax is for method shorthand is fairly new, introduced by the ES2015 specification. You can think of your example like this:
const injectedComp = {
inject: ['foo', 'bar'],
render: function render() {},
created: function created() {
injected = [this.foo, this.bar]
}
}
render () and created () are method definitions.
They are almost a shorthand for named functions:
const injectedComp = {
inject: ['foo', 'bar'],
render : function render() {},
created: function created () {
injected = [this.foo, this.bar]
}
}
Method definitions are nearly identical to functions, except that they are not constructable.
So you could not write new injectedComp.render() for your example.

socket.io and vue.js fetching data

I am trying to fetching the data of vue.js using this
fetchData: function () {
socket.emit('getAllSongs')
socket.on('allSongs',function(data) {
this.songs = data
});
}
FetchData is called when the vue app is created
created: function () {
this.fetchData();
}
But when I try to call the variable songs outside socket.on it stills empty.
What could I do?
Try changing you fetchData function to this:
fetchData: function () {
socket.emit('getAllSongs')
var that = this;
socket.on('allSongs',function(data) {
that.songs = data
});
}
The reason is the value this is different in the callback context and is not the component object which you expect it to be.
I think you need to bind this to the end of your function or to use ES6 arrow syntax =>
socket.on('allSongs',function(data) {
that.songs = data
}.bind(this));
socket.on('allSongs',data => {
that.songs = data
});

Load new JSON data and replace the old one in VueJS

I'm using a v-for loop with data fetched from JSON file. Is there a way to re-render the DOM and whole v-for loop after loading a new JSON file and replacing the old one?
What I'm trying to achieve is load different sets of products on click and update DOM.
Vue.use(VueResource);
var productsList = new Vue({
el: '#vue',
data: function () {
return {
products: []
};
},
ready: function () {
this.$http.get('data/data.json').then(function (response) {
this.products = response.data;
});
},
methods: {
loadProducts: function (url) {
this.$http.get(url).then(function (response) {
this.products = response.data;
});
}
}
});
The code above should be sufficient for updating your DOM automatically. There are 2 errors however and 1 thing you should consider.
Anonymous functions have different scopes in javascript. This means that when you have an anonymous function function(response) then you lose the scope of the vue instance this. In order to deal with such situations you have to either use arrow functions if you have support for them in your project or save this into another variable before entering the anonymous function.
Vue.use(VueResource);
var productsList = new Vue({
el: '#vue',
data: function () {
return {
products: []
};
},
ready: function () {
var self=this;
this.$http.get('data/data.json').then(function (response) {
self.products = response.data;
});
},
methods: {
loadProducts: function (url) {
var self=this;
this.$http.get(url).then(function (response) {
self.products = response.data;
});
}
}
});
Also if you have this exact code, you should've received an error in browser with products being undefined.
Once you update the products data it will automatically change the DOM as par the latest data, as vue data is reactive. One error I see in your code is, you may have wrong this inside the this.$http block. instead of using function() syntax, use arrow function, which does not bind it's own this, arguments, super, or new.target, like following:
Vue.use(VueResource);
var productsList = new Vue({
el: '#vue',
data: function () {
return {
products: []
};
},
ready: function () {
this.$http.get('data/data.json').then((response) => {
this.products = response.data;
});
},
methods: {
loadProducts: function (url) {
this.$http.get(url).then( (response) => {
this.products = response.data;
});
}
}
});

Categories

Resources