VueJS this in lodash throttled method - vue.js

I am trying to throttle a method in my VueJS application. I tried the following at first:
export default {
data () {
return {
foo: 'bar'
}
},
methods: {
doSomething () {
console.log('olas')
}
},
created () {
_.throttle(this.doSomething,200)
}
}
But the doSomething method was just not fired: https://jsfiddle.net/z4peade0/
Then, I tried this:
export default {
data () {
return {
foo: 'bar'
}
},
methods: {
doSomething: _.throttle( () => {
console.log('olas')
},200)
},
created () {
this.doSomething()
}
}
And the functiong gets triggered: https://jsfiddle.net/z4peade0/1/
Problem is, I can't access the foo property inside the throttled method:
export default {
data () {
return {
foo: 'bar'
}
},
methods: {
doSomething: _.throttle( () => {
console.log(this.foo) // undefined
},200)
},
created () {
this.doSomething()
}
}
I tried to do something like:
const self = {
...
methods: {
doSomething: _.throttle( () => {
console.log(self.foo)
},200)
},
...
}
export default self
without success
How could I use lodash throttled method on a VueJS method, and using this context?

You're using an arrow function, which binds the wrong context (this). You should use a plain function:
doSomething: _.throttle( function () {
console.log('olas', this.foo);
},200)

Related

vuejs use data from parent, but parent data usually update

there are two .vue file and one is parent and another is child.
I am developing 'Sending file' function with Modal.
I will upload file data in parent.vue.
and when I click 'Send', child.vue will be popped up!
and I will choose, target who receive this file data.
and finally, I click 'Send' button, get connection to Backend server.
This is parent.vue
<<templete>>
<script>
export default {
name: 'BillingView',
components: {
EmailSender
},
data() {
return {
uploaded_file: '',
file_data: {},
is_uploaded: false,
popupVal: false
}
},
methods: {
sendEmail() {
if (this.is_uploaded == false) {
alert('Upload your file');
} else {
<< parsing file data>>
this.file_data = JSON.parse(JSON.stringify(this.parsed_uploaded_file));
this.popupVal = (this.popupVal) ? false : true
}
},
popupClose: function ( value ) {
this.popupVal = value
}
}
}
</script>
This is child.vue
<<templete>>
<script>
import axios from 'axios';
export default {
name: 'EmailSender',
props: {
popupVal: Boolean,
file_data: {
type: Object,
default: () => {
return {}
}
}
},
data: () => ({
}),
computed: {
popUp: {
get() {
return this.popupVal
},
}
},
created() {
},
methods: {
sendEmail() {
let req_data = {};
req_data ['file'] = file_data;
axios.post(process.env.VUE_APP_BASE_API + 'email/',
{
req_data ,
headers: {
'Content-Type': 'application/json;charset=UTF-8-sig'
}
}
).then(res => {
console.log('SEND EMAIL SUCCESS!!');
console.log('SEND EMAIL RESPONSE::', res, typeof (res));
})
.catch(function () {
console.log('SEND EMAIL FAILURE!!');
});
}
}
};
</script>
but here, "req_data ['file'] = file_data;" the file_data is empty, {}.
I expect when I update file_data in parent vue, child can know and use updated file data.
how can I do?
You have to make sure you send file_data as a prop to your component. e.g. Your component is 'myPopup' and you should use it as below to send file_data as a prop:
<myPopup :myData="file_data" >
In this case, you can get file_data as 'myData' in the child component as below
After changes, your props should be:
props: {
myData: {
type: Object,
default: () => {
return {}
}
}
},
Your function should be:
Also, don't forget to use 'this' keyword. this.myData instead of myData in function.
methods: {
sendEmail() {
let req_data = {};
req_data['file'] = this.myData;
// axios here
};
},

How to insert a function into a directive Vue 3?

I need to write a specific global directive that should perform the same function in different hooks.
How can I implement something like this
export default {
directives: {
widthAsChild: {
widthAsChild(el) {
el.style.width = getComputedStyle(el.firstChild).getPropertyValue(
"width"
);
},
mounted(el) {
widthAsChild(el);
window.addEventListener("resize", () => {
widthAsChild(el);
});
},
},
},
}
The function has to be declared outside the directive's declaration object. One way to do that is to use an IIFE that contains a local method that you can can reuse in the returned directive declaration:
export default {
directives: {
widthAsChild: (() => {
const widthAsChild = el => {
el.style.width = getComputedStyle(el.firstChild).getPropertyValue("width");
}
return {
mounted(el) {
widthAsChild(el);
window.addEventListener("resize", () => {
widthAsChild(el);
});
},
}
})()
}
}
demo 1
Alternatively, you could move that to a separate file:
// #/directives/widthAsChild.js
const widthAsChild = el => {
el.style.width = getComputedStyle(el.firstChild).getPropertyValue('width')
}
export default {
mounted(el) {
widthAsChild(el)
window.addEventListener('resize', () => {
widthAsChild(el)
})
}
}
// MyComponent.vue
import widthAsChild from '#/directives/widthAsChild'
export default {
directives: {
widthAsChild,
}
}
demo 2

Vue dynamic component template not working for promise

<template>
<component :is="myComponent" />
</template>
<script>
export default {
props: {
component: String,
},
data() {
return {
myComponent: '',
};
},
computed: {
loader() {
return () => import(`../components/${this.component}`);
},
},
created() {
this.loader().then(res => {
// components can be defined as a function that returns a promise;
this.myComponent = () => this.loader();
},
},
}
</script>
Reference:
https://medium.com/scrumpy/dynamic-component-templates-with-vue-js-d9236ab183bb
Vue js import components dynamically
Console throw error "this.loader() is not a function" or "this.loader().then" is not a function.
Not sure why you're seeing that error, as loader is clearly defined as a computed prop that returns a function.
However, the created hook seems to call loader() twice (the second call is unnecessary). That could be simplified:
export default {
created() {
// Option 1
this.loader().then(res => this.myComponent = res)
// Option 2
this.myComponent = () => this.loader()
}
}
demo 1
Even simpler would be to rename loader with myComponent, getting rid of the myComponent data property:
export default {
//data() {
// return {
// myComponent: '',
// };
//},
computed: {
//loader() {
myComponent() {
return () => import(`../components/${this.component}`);
},
},
}
demo 2

(Vue.js) In computed, I can't use data

export default {
data () {
return {
test: true
}
},
computed: {
test2: {
get: () => {
return console.log(this.test)
},
set: () => {
console.log(this.test)
}
}
}
But the Error occurred TypeError: Cannot read property 'test' of undefined
I want to use data in computed. but I can't
Help Me!
You should not be using arrow functions in the getter and setters, because that refers to the lexical this:
Note that if you use an arrow function with a computed property, this won’t be the component’s instance
So, update your code:
export default {
data () {
return {
test: true
}
},
computed: {
test2: {
get: function () {
return console.log(this.test)
},
set: function () {
console.log(this.test)
}
}
}
this here refers to the function not vue instance ,you can make this:
test2: {
let This = this
get: () => {
return console.log(This.test)
},
set: () => {
console.log(This.test)
}
}

can't write api method in data() vue

I want USD to be taken from api which function I've in methodsbut how can I write it ?
data(){
return {
posts: 1,
USD:changeCurrency()
}
},
methods: {
changeCurrency: function () {
axios.get('http://data.fixer.io/api/latest?access_key=509c9d50c1e92a712be9c8f1f964cf67')
.then(response => {
this.posts = response.data.rates.GEL.toFixed(3)
})
}
That is not how data is supposed to be used.
You can call changeCurrency in mounted or in the component itself #click="changeCurrency"
{
data() {
return {
posts: 1,
// USD:changeCurrency()
};
},
mounted() {
// you could call here instead
this.changeCurrency();
},
methods: {
changeCurrency: function () {
axios.get('http://data.fixer.io/api/latest?access_key=509c9d50c1e92a712be9c8f1f964cf67')
.then(response => {
this.posts = response.data.rates.GEL.toFixed(3);
});
}
}
}