In a Vue 2 project using Storybook, a component is using composition API and emits an event:
export default Vue.extend({
setup(_, { emit }) {
//some code
emit('myEvent');
}
});
I can't find a way to document this myEvent emited event. All of the examples from the Vue Styleguidist are with the Option API.
I would like to add this event to an event' s section in the storybook page, something like
Anyone knows if this is possible?
I am using storybook/vue 6.5.8.
Related
Is this instance lifecycle hooks diagram also valid(the same) for a vue.js single file component or a global component(vue.componnet())? or is it only used for a Vue instance(new Vue)??
thanks.
Yes, these lifecycle hooks are there for all vue instances: SFCs, global components, explicit new Vue, vue-test-utils wrappers, and so on.
The only thing that SFC do are to write the .render method for you because it's way simpler to write it with an html-like syntax rather than write the render function manually.
In an SFC, you'd tap into them as such:
<script>
export default {
created() {
// do something on created
}
}
</script>
In an explicit new Vue, like this:
new Vue({
created() {
// do something on created
}
});
You get the point.
I recently came across this blog post: Stop using Page Objects and Start using App Actions. It describes an approach where the application exposes its model so that Cypress can access it in order to setup certain states for testing.
Example code from the link:
// app.jsx code
var model = new app.TodoModel('react-todos');
if (window.Cypress) {
window.model = model
}
I'd like to try this approach in my VueJS application but I'm struggling with how to expose "the model".
I'm aware that it's possible to expose the Vuex store as described here: Exposing vuex store to Cypress but I'd need access to the component's data().
So, how could I expose e.g. HelloWorld.data.message for being accessible from Cypress?
Demo application on codesandbox.io
Would it be possible via Options/Data API?
Vue is pretty good at providing it's internals for plugins, etc. Just console.log() to discover where the data sits at runtime.
For example, to read internal Vue data,
either from the app level (main.js)
const Vue = new Vue({...
if (window.Cypress) {
window.Vue = Vue;
}
then in the test
cy.window().then(win => {
const message = win.Vue.$children[0].$children[0].message;
}
or from the component level
mounted() {
if (window.Cypress) {
window.HelloWorld = this;
}
}
then in the test
cy.window().then(win => {
const message = win.HelloWorld.message;
}
But actions in the referenced article implies setting data, and in Vue that means you should use Vue.set() to maintain observability.
Since Vue is exposed on this.$root,
cy.window().then(win => {
const component = win.HelloWorld;
const Vue = component.$root;
Vue.$set(component, 'message', newValue);
}
P.S. The need to use Vue.set() may go away in v3, since they are implementing observability via proxies - you may just be able to assign the value.
Experimental App Action for Vue HelloWorld component.
You could expose a setter within the Vue component in the mounted hook
mounted() {
this.$root.setHelloWorldMessage = this.setMessage;
},
methods: {
setMessage: function (newValue) {
this.message = newValue;
}
}
But now we are looking at a situation where the Cypress test is looking like another component of the app that needs access to state of the HelloWorld.
In this case the Vuex approach you referenced seems the cleaner way to handle things.
I'm building server UI and I'm struggling with components. Maybe someone knows how to stack all components and control all UI with functions?
example
App.vue
chat.vue
hud.vue
player.vue
I need to display all .vue in app.vue
App.vue
import chat from './components/chat.vue'
export default {
name: 'app',
components: {
chat
}
}
chat.vue
export default {
methods: {
test: function() {
console.log("test");
}
}
}
How can I call the function test in the DevTools console, when I run the webiste?
Do you know about the Vue Dev Tools browser extension? That will let you inspect all components on a page and tweak their data/props.
I don't think it will let you call their methods, but if you need to call one of those methods in the console you might try (temporarily, for testing purposes) making a component instance available on the window inside a mounted lifecycle function.
EDIT: Is that your entire App.vue, by the way? I'm thinking maybe I misunderstood your question and you think that...
components: {
chat
}
...means that it should render the component on the page. It only makes it available for the parent component to use. You have to place it inside a <template> to actually render it.
In my custom library I have several components which run ajax requests, and when a given request fails the component emits an error event.
Then, in my main component I want to listen to all error events emmited and run the method handleErrors, but for that I have to go on every component and add #error="handleErrors".
Is there a way to configure my main component to catch error events dynamically and call handleErrors without going on each component and adding it? Preferrably changes to the main component only.
You can use the EventBus system in Vue instance. Actually EventBus is a different Vue instance your Main Vue instance. You make your own Event bus system.$emit, $on and $off events.
event-bus.js
import Vue from 'vue';
export const EventBus = new Vue();
and now you are ready to use.
some-component.vue
// Import the EventBus.
import { EventBus } from './event-bus.js';
// Send the event on a channel (eventName) with a payload (the click count.)
EventBus.$emit('eventName', this.clickCount);
other-component.vue
// Import the EventBus.
import { EventBus } from './event-bus.js';
// Listen for the eventName event and its payload.
EventBus.$on('eventName', clickCount => {
console.log(clickCount)
});
// Stop listening.
EventBus.$off('eventName');
more information and example
https://alligator.io/vuejs/global-event-bus/
Figured a way to do it without refactoring the individual components: just injected the listener in every component using a mixin.
The result:
// Before starting up the main instance:
Vue.mixin({
created: function() {
this.$on('error', function(error) {
// Then I handled the errors here.
);
}
});
Hy there. Given webtorrent.io I would like to build a VueJS component that shows loading magnet files, and status and also when downloads finishes triggers players.
Is the Vuex Store a good place to keep a list of active download queues and a stream o data?
All that is possible with webtorrent.
var WebTorrent = require('webtorrent')
var client = new WebTorrent()
var magnetURI = 'magnet: ...'
client.add(magnetURI, { path: '/path/to/folder' }, function (torrent) {
torrent.on('done', function () {
console.log('torrent download finished')
})
})
How could I structure that architecture/pattern with VueJS? Any insights, apreciated
Thanks!
I will answer cause I found a solution. Then if the community wants this to be deleted, its all right.
Basically what I did is wait for a Component to be mounted.
Inside AComponent.Vue
<template>
<keep-alive>
<!-- HTML binding webtorrent client data -->
</keep-alive>
</template>
<script>
export default {
mounted() {
var client = WebTorrent()
}
}
</script>
Why this achieve what I was looking for ? :
keep alive keep that parts of the DOM alive, when i render another template and come back to this one (as if the download queue is in a widget, modal, or another view that needs to keep alive).
mounted, its part of the component lifecycle hooks (https://v2.vuejs.org/v2/guide/instance.html#Lifecycle-Diagram), and happens once the DOM has been maniuplated, window exists (needed by WebTorrent), and the component has been rendered.