Jest + Vue vm properties and methods unresolved in IntelliJ - vue.js

My Vue Component:
data() {
return {
test: false,
}
},
methods: {
setTestToTrue() {
this.test = true
},
My JestJs test
Is there any way to get rid of the warnings?

This would require adding special support for wrapper.vm, as the methods are added dynamically in runtime and thus can't be resolved statically
Please vote for WEB-51228 to be notified on any progress with it

Related

Vue component replacement on load and scroll - how to make it work?

I inherited app written in VUE and mostly I found my way through the app to make designed changes, but I have problem with the below code.
What I want to achieve is: on scrolling the new tiles are being loaded and they have elements which should be replaced as in vueComponent function.
It works as designed on document load, but new elements are not being replaced. I haven't copied all the code, but you can get an idea. Please see my comments below to know what is working and what is not.
$(document, context).once('vue__comparison_toggle_add').each(() => {
Drupal.behaviors.vue__comparison_toggle.vueComponent(); //this works perfectly
});
$(window).on("scroll", function() {
Drupal.behaviors.vue__comparison_toggle.vueComponent(); //this doesn't although the function is entered
});
},
vueComponent: function () {
Vue.component('comparison-training-toggle', {
template: this.template,
props: ['trainingId', 'icon', 'init-comparison'],
data() {
return {
inComparison: false,
}
},
computed: {
toggleText() {
return this.inComparison ? Drupal.t('Usuń z porównania') : Drupal.t('Dodaj do porównania')
}
},
methods: {
toggle() {
...

Can not catch Vuex state change in my Vue component

I have a Vuex store where I have a getter which works correctly and I can see the changes on the state. But if I call this getter as computed property in component it does not work. The value is still the same.
The store code looks like:
mutations: {
UPDATE_SERVER_FILTERS(state, payload) {
this._vm.$set(state, 'serverFilters', payload);
//state.serverFilters = payload; // Both patterns work
},
getters: {
serverFilters(state) {
return state.serverFilters; // This works fine
}
}
}
The component code:
computed: {
serverFilters() {
return this.$store.getters[this.storeName + '/serverFilters'];
},
}
Here is JSFiddle example https://jsfiddle.net/camo/je0gw9t3/4/ which works fine. And it is a problem cause in my project it does not work. I am prepared to die...
How can I solve it?
In the most bottom part:
new Vue({
store,
el: '#example',
data() {
return {};
},
computed: {},
methods: {
changeFilters() {
this.$store.dispatch(this.storeName + '/updateFilters');
// ^^^^^^^^^^^^^^ there is no storeName
},
},
});
The changeFilters method. You are using this.storeName, but there is no this.storeName! Just like the Child component, add storeName: 'a' to the data() then it should work.
https://jsfiddle.net/4yfv3w87/
Here is the debug process for your reference:
First open the Vue Devtools and switch to the timeline tab. And just click the button, you will see that there is no action is being fired. So the problem must be the one who dispatches the action. And then you will notice that the root component doesn't have a storeName.
So don't panic, just try to trace the code. It will only take a few minutes to find out the issue!
Computed properties might have problem to make an observer reference from returned value out of function. Instead of chaining getters and computed properties, why you don't use just getters or computed properties ? In my opinion, it's a bad practice to use them both, and I can't imagine a situation you need it. So if you need filter operations in many components, just make a getter and use getter in components instead of computed properties.
If you really want to chain them, try this:
new Vue({
store,
el: '#example',
data() {
return {
storeName: 'a'
}
},
computed: {
filters() {
get() {
return this.$store.getters[`${this.storeName}/getFilters`];
}
set(newValue) {
this.$store.dispatch(this.storeName + '/updateFilters');
}
},
},
})
Comment please if someone check it. I don't know are it works.

How can I fill an array by calling a method in Vue js?

I am trying to fill an array, declared in data property, by calling a function in methods property in Vue js. Here is the code:
<script>
export default {
extends: Bar,
mounted() {
this.renderChart(this.chartData, this.options);
this.fillLabel();
},
data() {
return {
chartData: {
labels:[],
datasets: [
{
label: "Users",
data: [40,20,12,39,10,40]
}
]
},
};
},
methods: {
fillLabel() {
this.chartData.datasets[0].data.map(function (key,value) {
this.chartData.labels.push(key);
})
}
}
};
</script>
But this gives me following error in console :
[Vue warn]: Error in mounted hook: "TypeError: Cannot read property 'chartData' of undefined"
So how can I fill the labels array(inside chatData) by 0 to length of data array(inside datasets).
I am looking for your help. Thanks in advance.
This is due to the fact that your function inside your map function will loose the this context. and so its getting undefined.
to solve this problem use an arrow function inside your map.
this.chartData.datasets[0].data.map((key,value)=> {
this.chartData.labels.push(key);
})
this will solve the problem
Only need to introduce this to your fillLabel method as below:
I tried this solution nd it fixed the problem
fillLabel() {
let th = this;
th.chartData.datasets[0].data.map(function (key,value) {
th.chartData.labels.push(key);
})
alert(th.chartData.labels)
},

Adding classes to body using lifecycle hooks in vueJS

I use beforeCreate and beforeDestroy hooks in order to add classes to body. In some cases I need to add classes, in some not.
So I have such code in each component which requires this functionality:
beforeCreate() {
document.body.classList.add('has-background')
},
beforeDestroy() {
document.body.classList.remove('has-background')
}
The problem is that if I navigate from one route to another, say from A component to B component, the beforeCreate of the B component executed first, and then beforeDestroy of the A component, which removes the has-background class.
How can I solve the issue?
Try using nextTick()
beforeCreate() {
this.$nextTick().then(() => document.body.classList.add('has-background'))
},
Edit:
I also suggest to use created() rather than beforeCreated(). But to achieve the best behavior, it is best to use mounted()
I have the same issue on my project and I have applied something like this.
methods: {
toggleBodyClass(addRemoveClass, className) {
const el = document.body;
if (addRemoveClass === 'addClass') {
el.classList.add(className);
} else {
el.classList.remove(className);
}
},
},
mounted() {
this.toggleBodyClass('addClass', 'mb-0');
},
destroyed() {
this.toggleBodyClass('removeClass', 'mb-0');
}

babelify 6 with browserify and the es2015 preset is not working

I am attempting to use the new babel release, and while trying to use the es2015 preset babel doesn't seem to be able to understand arrow functions?
My setup on pre-babel6 was as follows:
transform: [['babelify', {sourceMap: false, stage: 0, optional: 'runtime', ignore: ["*.min.js"]}]]
and with babel6
transform: [['babelify', {"presets": ["es2015"]}]]
which does not work. Why is this?
edit
adding "stage-0" got rid of the syntax error messages, but has stoped me from being able to extend anything with the error: 'this' is not allowed before super() when I have infact got a super() call.
edit
Set up a simple test application with some es7 and tried to use the babel-core require hook, same problem.
edit
Ok so I have narrowed it down to stage-0 working differently in babeljs 6^.
Here is what I have noticed:
Run file
require("babel-core/register")(
{
presets: ["es2015", "stage-0"]
}
);
require("./app.js");
Works with:
class extendable {
constructor() {
console.log('extended')
}
}
class app extends extendable {
constructor() {
super();
this.method();
this.method2();
}
method() {
// arrow functions
setTimeout(() => {
console.log("works")
}, 1000)
}
/**
* arrow function method
*/
method2 = () => {
console.log('works')
}
}
new app();
Doesn't work with:
class extendable {
constructor() {
console.log('extended')
}
}
class app extends extendable {
constructor() {
super();
this.method();
this.method2();
}
method() {
// arrow functions
setTimeout(() => {
console.log("works")
}, 1000)
}
/**
* arrow function method
*/
method2 = () => {
// give an error: 'this' is not allowed before super()
this.state = "hello";
}
}
new app();
So I am a little confused. Is this really incorrect syntax? How have I been able to use this pre-babel6?
This is a Babeljs bug
See
Subclasses with class properties (without constructor) error #2942
[Regression BUG] Class scoped function showing SyntaxError: 'this' is not allowed before super() #2971
Hopefully this will see a fast fix.
edit #2942 is not referencing the same bug. Here is an issue following this bug: #3028
It depends a bit on how you are executing browserify, this is what the Github repository from babelify (https://github.com/babel/babelify) says about it :
From the CLI:
$ browserify script.js -o bundle.js \
-t [ babelify --presets [ es2015 react ] ]
With Node:
browserify("./script.js")
.transform("babelify", {presets: ["es2015", "react"]})
.bundle()
.pipe(fs.createWriteStream("bundle.js"));