Vue.js override mounted() method - vue.js

So I've extended my component this way:
<template>
<qlist></qlist>
</template>
<script>
import QuestionList from '#/components/pages/questions/QuestionList'
export default {
extends: QuestionList,
components: {
'qlist': QuestionList
}
}
</script>
<style scoped>
</style>
How can I totally override mounted() method from my QuestionList component? I've noticed that when I define it in current component, I can add functionality to the mounted() method, but I'm not able to override the previous behaviour

Your component imports QuestionList to include it as an ELEMENT in the template, so whatever you have in the mounted() hook of QuestionList will be called, you cannot avoid it doing it this way. Use a mixin instead: put all the logic in there that should be the same in both the original component and the component that extends it and separately implement mounted() in each. By moving your mounted() hook logic to a method you could even use the custom merge options as described here: https://v2.vuejs.org/v2/guide/mixins.html but it's probably not necessary.

Related

VueJS extend component for customization

Is there any way to use some Generic component and keep it's props emitters etc and just customize it?
Example:
<template>
<GenericComponent color="black">
Something in the default slot
</GenericComponent>
</template>
<script>
import GenericComponent from 'GenericComponent'
export default {
name: 'MyCustomizedComponent'
props: // to take same props as GenericComponent and pass it to GenericCompnent?
// and it emits all events from GenericComponent
// I could probably just copy props and pass it directly to GenericComponent, but what if there
// is many
}
</script>
<style scoped>
//some changes to Generic component
<style>
So I could just create props, and define all # from GenericComponent and emit them same way, but is there any easy way to do it ?
You can either use mixins, to reuse code across several components.
You can also create a wrapper component to the original component, do your customizations, and use v-bind="$props" to propagate all props to the original component and v-on="$listeners" to emit all events from the original component to the parent.
I'm not sure what is best for your case.

Dynamic component inside a component that is rendered with render() function

I saw in the docs that you can have a dynamic component inside your VueComponent like this :
<component :is="componentName" v-bind="componentProps" #custom-event="doSomething" />
I am trying to have one of these dynamic components inside a dynamically rendered component (with the render() function, not with an HTML template). Without too much hope, I've tried this :
render(createElement: CreateElement) {
return createElement('component', props: {
'is': 'TestComponent'
});
}
but I got
[Vue warn]: Unknown custom element: <component> - did you register the component correctly?
So again, not hoping too much for a miracle, I tried to import Component and declare it as a component :
#Component({
components: {
Component,
TestComponent
}
})
export default class DynamicThingy extends Vue {
render(createElement: CreateElement): VNode {
return createElement('Component', {
props: {
'is': 'TestComponent'
}
});
}
}
But then I get
[Vue warn]: Do not use built-in or reserved HTML elements as component id: Component
Any idea how that could be possible ?
The first parameter of createElement() must be either
An HTML tag name,
component options,
or async function resolving to one of these.
https://v2.vuejs.org/v2/guide/render-function.html#createElement-Arguments
So in a render function, you can simply create a function* that returns one or another component's options based on your desired criteria, and let that be your first argument. *This function is identical to the function you'd write to determine what goes into the :is prop)
You only need the dynamic component <component /> and :is prop in a template where you don't have the possibility to do it programmatically.
You can use this smart-list component from the vue docs as an example.

Sub-class a vue component

I have some repeating functionality that many components will use. So my first thought is I should create a base component and have my components inherit/subclass from this.
But maybe this is not possible in vue.js and maybe its not the vue.js way to do things? If I explain my use-case can you suggest how best I implement this in vue.js?
BasePage.vue
<template>
...
</template>
<script>
export default {
name: 'animated-page',
watch: {
'$route' (to, from) {
// conditionally choose animations depending on route
const toDepth = to.path.split('/').length
const fromDepth = from.path.split('/').length
this.transitionName = toDepth < fromDepth ? 'slide-right' : 'slide-left'
}
}
}
</script>
<style>
... my animations
</style>
About.vue
<template>
...
</template>
<script>
export default {
// somehow inherit from BasePage
name: 'about-page',
... 'about' specific code
}
</script>
<style>
</style>
You can use extend to subclass the Vue constructor, and you can use it on components to subclass them.
In general, though, you should prefer composition to inheritance and use mixins where you can.
Mixins are a flexible way to distribute reusable functionalities for Vue components. A mixin object can contain any component options. When a component uses a mixin, all options in the mixin will be “mixed” into the component’s own options.

Pass #EventListener to Component via Vuejs Router

Before I used vuejs-router, I've loaded component in app this way:
<my-component #done="doneForm"
#cancel="cancelForm"></my-component>
Well, I want to use vuejs-router to load my-component. So, how can I pass #done and #cancel to my-component via vuejs-router?
You need to define a route to which your my-component will be instantiated. This component will contain the done and cancel callbacks, so:
var router = new VueRouter({
routes: [
{ path: '/someRoute', component: SomeComponent }
]
]
SomeComponent would be something like:
<template>
<my-component #done="doneForm" #cancel="cancelForm"></my-component>
</template>
<script>
import MyComponent from '/some/path/components/MyComponent'
export default {
components: {
myComponent: MyComponent
},
methods: {
doneForm () {
console.log('Form Done')
},
cancelForm () {
console.log('Cancel Form')
}
}
}
</script>
As you've not shown any code and how you're calling your <my-component> but the whole point is that the <my-component> needs to be instantiated somewhere within another component that can have hold the cancelForm and doneForm methods. If you didn't want these callbacks then you could set a route up to go straight to that component.
Another option is to make thing stateful using Vuex. You could remove the callbacks from the component and when the form is done within <my-component> set something in the state that you can react to somewhere else in your app. You could also do the same with events and raise an event to listen for and do something.

Is there a thing in Vuex that work the same as mapDispatchToProps in Redux?

I was trying to do things like this.updateData() instead of this.$store.dispatch() in a child component, where the updateData is a function inherits from its parent component. Anyone have any idea how to achieve that?
So to update data of parent comp. from child component in Vue we can utilize event bus:
Parent:
<template>
Hi Blake...
<child-component #trigger="updateData()"></child-component>
</template>
<script>
export default {
mounted() {},
methods: {
updateData: function() {
// this will be triggered from child
}
}
}
</script>
Child ( child-component ):
<template>
<button #click="$emit('trigger')">Trigger Parent Function</button>
</template>
<script>
export default {
mounted() {}
}
</script>
Now this only triggers parent function but you can also send data with event that will be received by parent. This is just Vue without Vuex. If I'm wrong and you're not looking for this maybe you want to use Vuex mapActions which can be used to import all Vuex actions you need in your component and use them as this.vuexAction instead of this.$store.dispatch('vuexAction').
I hope I helped. Good luck.