In main.js i created the eventBus
Vue.prototype.$eventHub = new Vue()
And in component1
this.$eventHub.$emit('logged-in')
In component2, i tried this
beforeMount () {
this.$eventHub.$on('logged-in', function () {
console.log("logged in")
})
},
beforeDestroy() {
this.$eventHub.$off('logged-in')
}
It is not printing any thing in the console. If i remove this.$eventHub.$off('logged-in') it is working fine, but it is executing number of times that$emit is executed. What am i doing wrong here? why $off is not working?
Unable to pass the parameters as well
trying to send message using $emit
this.$eventHub.$emit('logged-in', "some message")
in $on
this.$eventHub.$on('logged-in', this.testEvent)
The test event method looks
testEvent (params) {
console.log(params)
}
The params shows undefined.
But if i do this, it is working fine
this.$eventHub.$on('logged-in', (params) => {
console.log(params)
})
How can i pass parameters to the method?
You should pass a reference to $off
beforeMount () {
this.$eventHub.$on('logged-in', this.onEventHandler)
},
beforeDestroy() {
this.$eventHub.$off('logged-in', this.onEventHandler)
},
methods: {
onEventHandler () {
console.log("logged in")
}
}
Related
I'm trying to use fixtures to hold data for different tests, specifically user credentials. This is an example of the code. I'm getting 'Cannot read properties of undefined (reading 'data')'. I tried to google search , I found Cypress fixtures - Cannot read properties of undefined (reading 'data')
I used closure variable technique as reccomended in that post , yet I got reference error of unable to reference data.Please help me.I know cypress.config can be used but I want to keep that for global configs
Json(credentials.json):
{
"username":"*****",
"password":"*****"
}
Code:
import { LoginPage } from "./pageobject/login_page"
describe('Test Scenario', () => {
before(function () {
cy
.fixture('credentials').then(function (data) {
this.data = data
})
})
it('Simple login', () => {
cy.visit(Cypress.env('url'))
var loginpage = new LoginPage()
loginpage.EnterUsername(this.data.username)
loginpage.clickonSubmit()
loginpage.EnterPassword(this.data.password)
loginpage.clickonSubmit()
Cypress
.on('uncaught:exception', (err, runnable) => {
return false;
});
cy.
wait(10000)
cy.
get('span[id="user"]').should('have.text', this.data.username , 'User Login Unsuccessfully')
});
});
There's a few things need adjusting
use function () {} syntax in the it() block
use beforeEach() and alias to load the fixture, because data on this can be cleared (especially after login)
move uncaught:exception catcher to the top of the block
don't cy.wait(), instead add timeout to next command
.should() only has two parameters in this case, so use .and() to test the 2nd text
import { LoginPage } from './pageobject/login_page';
describe('Test Scenario', () => {
beforeEach(function () {
cy.fixture('credentials').as('data')
})
it('Simple login', function() {
Cypress.on('uncaught:exception', (err, runnable) => {
return false;
});
cy.visit(Cypress.env('url'));
var loginpage = new LoginPage();
loginpage.EnterUsername(this.data.username);
loginpage.clickonSubmit();
loginpage.EnterPassword(this.data.password);
loginpage.clickonSubmit();
cy.get('span[id="user"]', {timout:10_000})
.should('have.text', this.data.username)
.and('have.text', 'User Login Unsuccessfully')
})
})
I suspect it's because you are using an arrow function instead of a regular function, you cannot access the this object with an arrow function.
Cypress docs
If you store and access the fixture data using this test context
object, make sure to use function () { ... } callbacks. Otherwise the
test engine will NOT have this pointing at the test context.
change it to this:
it('Simple login', function() {
...
});
I'm currently trying out react-query in my project.
I'm having trouble with handling errors within my mutation.
In my networks tab, I can confirm that the server is responding with code 400 or 500, which I assumed makes axios throw an error, thus firing the defined onError function.
However, the onSuccess function is always called no matter how the API call goes.
What am I missing here? Thanks in advance.
const { mutate } = useMutation(
['mutation'],
() => axios.patch(API_URL, params),
{
onSuccess: () => {
//this is always fired, even when response code is 400, 500, etc.
void queryClient.invalidateQueries('query');
},
onError: () => {
//should do something but never fired
},
}
);
A simple approach would be to manage the status code in the onSuccess callback.
It's a bug in the useMutation which I am also facing so I manage the status code in conditionals. But it should work not work in case of 500. There is a
flaw in your implementation then.
Make sure to return the result of your mutation function (i.e. the axios.patch call needs to be returned)
const { mutate } = useMutation(['mutation'], () => return axios.patch(API_URL, params),
{
onSuccess: () => {
//this is always fired, even when response code is 400, 500, etc.
void queryClient.invalidateQueries('query');
},
onError: () => {
//should do something but never fired
},
})
It might be because you're passing arguments in worng order.
In docs it says you should call it as follows:
useMutation(mutationFn, {
mutationKey,
onError,
onMutate,
onSettled,
onSuccess,
retry,
retryDelay,
useErrorBoundary,
meta,
});
Which makes your code as follows:
useMutation(
() => axios.patch(API_URL, params),
{
mutationKey: 'mutation',
onSuccess: () => {
//this is always fired, even when response code is 400, 500, etc.
void queryClient.invalidateQueries('query');
},
onError: () => {
//should do something but never fired
},
}
I am trying to pass a Vue function to the lodash throttle method. Shouldn't I just be able to do something like this?
When I am trying to do this I am getting the following error:
Error in callback for watcher "query": "TypeError: Expected a function"
Watcher
watch: {
query() {
throttle(this.autocomplete(), 400);
}
}
Methods
methods: {
autocomplete() {}
}
Even though I am passing a function reference I am still getting an error message. If I wrap it with a anonymous function it won't fire:
throttle(() => { this.autocomplete(); }, 400);
I just checked and the autocomplete function does actually seem to fire regardless of the error that it is not a function in my example at the top.
What is going wrong here?
Edit:
Jsfiddle: http://jsfiddle.net/yMv7y/2780/
You are passing the return value of this.autocomplete() (maybe undefined) and not the function reference. If you want to do the latter, you have to omit the brackets:
watch: {
query() {
throttle(this.autocomplete, 400);
}
}
Working approach:
var demo = new Vue({
el: '#demo',
data: {
query: ''
},
watch: {
query: function() {
this.autocomplete()
}
},
methods: {
autocomplete: _.throttle(function() {
console.log('test');
}, 50)
}
})
<script src="http://vuejs.org/js/vue.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>
<div id="demo" v-cloak>
<input type="text" v-model="query">
</div>
As #Bill Criswell commented,
This is creating a throttled function every time query changes. You
want to constantly call the same throttled function like the answer
below.
My guess is that you need to define the throttled function with a non-invoked callback in a variable, and then invoke that as a function:
var throttled = throttle(this.autocomplete, 400)
watch: {
query() {
throttled();
}
}
Just spent quite awhile trying to figure that one out...
I have a VueJS component text-editor that I call as such in my tests:
import Vue from 'vue';
import TextEditor from '../src/TextEditor.vue';
import expect, {spyOn} from 'expect';
describe("<text-editor>", (done) => {
beforeEach(() => {
this.vm = new Vue({
data: { hi: { text: "hi" } },
template: '<div><text-editor ref="texteditor" v-model="hi" #hide="hidecb"></text-editor></div>',
components: { 'text-editor': TextEditor },
methods: {
hidecb: function() {
console.log('hide');
}
}
}).$mount();
});
it("should call the #hide callback", (done) => {
let spy = spyOn(this.vm, 'hidecb');
// This call will trigger an this.$emit('hide') in the component
this.vm.$refs.texteditor.save();
Vue.nextTick(() => {
expect(spy).toHaveBeenCalled();
done();
});
});
});
Weird thing is, method hidecb does get called and I see "hide" on the console. But the spy will fail with the following error:
Error: spy was not called (undefined:29)
I checked and the callback is indeed called before nextTick. I should also point out that I am using Webpack, expectjs and karma.
Would someone be able to point out why the spy doesn't work?
im just using Vue.js to updates posts on a site im messing around with, this is what ive got so far (im still learning javascript, and not too great at it)
[app.js]
var Vue = require('vue');
Vue.use(require('vue-resource'));
var app = new Vue({
el: '#app',
components: {
'postlist' : require('./components/postlist/postlist.js')
}
});
[postlist.js]
module.exports = {
template: require('./postlist.template.html'),
data: function () {
return {
'search': '',
'posts' : {}
}
},
methods: {
'updatePosts' : function()
{
this.$http.get('api/posts', function(responce, status, request)
{
this.$set('posts', responce.data);
});
}
}
};
What I'm looking for is to have updatePosts fire off every x seconds, how do I do this?
ive tried doing this in the app.js
setInterval(function()
{
app.components.postlist.methods.updatePosts(); // doesnt work
app.postlist.updatePosts(); //doesnt work either
}, 500);
and tried putting the setInterval into the component itself
im pretty lost with this, whats the best way to achieve this?
updatePosts running every x seconds?
I have also trouble with scopes in Vue.
this should work
module.exports = {
template: require('./postlist.template.html'),
data: function () {
return {
'search': '',
posts: {}
}
},
methods: {
updatePosts: function () {
var self = this;
self.$http.get('api/posts', function(responce, status, request) {
self.posts = responce.data;
setTimeout(function(){ self.updatePosts() }, 2000);
});
}
},
created: function () {
this.updatePosts();
}
}
Functions in Vue works kinda different way, because your method updatePosts is not regular function. It is function defined in $vm.methods object. so It can't be called regularly like setTimeout($vm.updatePosts). Actually $vm.updatePosts doesn't exists. if you called it like $vm.updatePosts() it is different story. $vm instance automatically calls its method... So correct way is setTimeout(function(){ self.updatePosts() },2000)
You could start the request cycle in created or somewhere else in the lifecycle. It's also probably better to use recursion here so you can wait for the response to come back before you send off another one. I didn't test this code fully but it should work.
module.exports = {
template: require('./postlist.template.html'),
data: function () {
return {
'search': '',
posts: {}
}
},
methods: {
updatePosts: function () {
this.$http.get('api/posts', function(responce, status, request) {
this.posts = responce.data;
setTimeout(this.updatePosts, 2000);
});
}
},
created: function () {
this.updatePosts();
}
}