Call Method from Differnt Vue Component (file) - vue.js

I need to call method from different vue component which resides in different file I've tried with ref and didn't work for me and I know this might be simple but im new to vue please help me to do this task.
Both files reside in same folder
DefinitionManager - need to call method inside this component
methods: {
closeDrawer() {
this.drawer = false;
}
DefinitionMaker - I need to call above method by this component method
methods: {
CallDrawerMethod() {
Call Method from Definition Manager component
}

just add a ref in the child component and call that.
<template>
<div>
<DefinitionManager ref="definationManager"/>
</div>
<t/emplate>
<script>
import DefinitionManager from './DefinitionManager.vue'
export default {
components: {
DefinitionManager
},
methods: {
CallDrawerMethod() {
this.$refs.definationManager.closeDrawer();
}
}
}
</script>

Related

Vue.js Dynamically extend/replace child component method at runtime with access to parent scope

Is it possible to extend child component function at runtime in vue? I want to limit/stop child component function call based on parent scope logic (I want to avoid passing props in this specific case).
Overriding a component method is not a runtime solution/I can't have access to parent scope.
What I have tried and it does not working:
// Foo.vue
<template>
<button #click="func">Click me</button>
</template>
export default {
methods: {
func() {
console.log('some xhr')
}
}
}
// Bar.vue
<template>
<Foo ref="foo"/>
</template>
export default {
components: {Foo}
mounted() {
this.$nextTick(() => {
this.$refs.foo.func = function() {
console.log('some conditional logic')
this.$refs.foo.func()
}
})
}
}
For this usecase a better implementation would be defining the function in the parent itself and passing it through props. Since props are by default reactive you can easily control it from parent.
// Foo.vue
<template>
<button #click="clickFunction.handler">Click me</button>
</template>
export default {
name: 'Foo',
props: {
clickFunction: {
type: Object,
required: true
}
}
}
// Bar.vue
<template>
<Foo :clickFunction="propObject"/>
</template>
export default {
components: {Foo},
data() {
return {
propObject: {
handler: null;
}
};
}
mounted() {
this.$nextTick(() => {
if(some condition) {
this.propObject.handler = this.func();
} else this.propObject.handler = null;
})
},
methods: {
func() {
console.log('some xhr')
}
}
}
From what I managed to realize:
the solution in the code posted in the question really replaces the func() method in the child component. It's just that Vue has already attached the old method to the html element. Replacing it at the source will have no impact.
I was looking for a way to re-attach the eventListeners to html component. Re-rendering using an index key would not help because it will re-render the component with its original definition. You can hide the item in question for a split second, and when it appears you will receive an updated eventListener. However, this involves an intervention in the logic of the child component (which I avoid).
The solution is the $forceUpdate() method.
Thus, my code becomes the following:
// Foo.vue
<template>
<button #click="func">Click me</button>
</template>
export default {
methods: {
func() {
console.log('some xhr')
}
}
}
// Bar.vue
<template>
<Foo ref="foo"/>
</template>
export default {
components: {Foo}
mounted() {
this.$nextTick(() => {
let original = this.$refs.foo.func; // preserve original function
this.$refs.foo.func = function() {
console.log('some conditional logic')
original()
}
this.$refs.btn.$forceUpdate(); // will re-evaluate visual logic of child component
})
}
}

Vuejs copy dynamic components methods

I am trying to make a visual representation of a component library. I am using dynamic <component>s to render each component. However, as I am populating the component with its slots, I am running into issues due to parent methods missing.
I want the components to be usable (demo) therefore I need to compensate for this.$parent not working.
<template>
<component v-bind:is="'s-' + comp.name" v-bind="props" ref="comp"> <!-- this is the corrent parent-->
<div v-if="comp.slots">
<div
v-for="(slot, i) in comp.slots"
v-bind:key="i"
v-bind:slot="slot.name"
>
<div v-if="slot.type == 'component'"> <!-- childs parent -->
<de-mo v-bind:comp="slot" /> <!-- this is the child calling a method on the parent -->
</div>
<div v-html="slot.value" v-else></div>
</div>
</div>
</component>
</template>
<script>
export default {
name: 'deMo',
computed: {
props() {
if (this.comp.props) {
return this.comp.props.reduce((a, r) => {
a[r.name] = r.value
return a
}, {})
}
}
},
props: {
comp: {
type: Object,
required: true
}
},
methods: this.$ref.comp.methods, //<-- this is an error
mounted(){
console.log(this.$ref.comp.methods)
}
},
</script>
<style></style>
1) Is there a way to copy the methods from the parent into this "demo" component via the ref attr
2) Alternatively, is there a better method to produce the same results?
Thanks
you can try to spread parent methods in a beforeCreate lifecycle as at this point your parent will be created and your component is going to register its all methods,
beforeCreate() {
this.$options.methods = { ...this.$parent.$options.methods };
},
however you can not access any refs in this as refs are only registered after mount of the component.
Note: Any library should use provide and inject to communicate with their component instead of referencing the parent component directly.
You can use an Event bus to communicate between components that aren't directly related to each other. Also, this is the recommended way of communication from child to parent in Vue.
bus.js
import Vue from 'vue'
export default new Vue()
demo.vue // child component that wants to call a method in the parent
import Bus from './bus.js'
export default {
mounted () {
// [1] child component will emit an event in the bus when it want to call a method of parent
Bus.$emit('invoke-parent-fn', 'param')
}
}
parent.vue // parent component where you want to render other components dynamically
import Bus from './bus.js'
export default {
methods: {
fn (param) {
console.log('// do something ' + param)
}
},
mounted () {
// [2] parent will be listening to the bus event, when child will emit an event, the handler passed in to the listener will be invoked
// [3] invoke the required method in the handler
Bus.$on('invoke-parent-fn', param => this.fn(param))
}
}

Call a child component method from parrent using vue / composition api

I'm trying to build a reusable modal component in Vue using this composition API. The plan is to expose a few methods like toggleModal() to call on some event in a parent component.
I've written my method in both setup() and methods.
export default {
setup() {
const isModalOpen = ref(false);
const toggleModal = () => {};
return {
toggleModal,
};
},
methods: {
toggleModalMethod() {},
},
};
If I console.log() my modal component I can see that only my toggleModalMethod() from methods is exposed.
Is there a way to expose a child method and call it from a parent component?
It's expected that a property returned from setup will be available on component instance when a child is mounted.
Here is a demo:
<template>
<div>
<Modal ref="modal"/>
<button #click="toggle">Toggle</button>
</div>
</template>
<script>
...
export default {
...
methods: {
toggle() {
this.$refs.modal.toggleModal();
}
}
};
</script>
Accessing child's members from a parent via a ref is considered an edge case, although exposing modal toggle function as public method is widely accepted scenario.

`v-on:click` bind to function in module

I am totally new to Vuejs and my question is:
Is there anyway for v-on to listen on click event, then execute a function which is defined in a module?
For example:
<button v-on:click="executeClick()"></button>
Will execute executeClick() in below module, which will be imported to Vue instance through require:
module.exports = {
executeClick: function () {
// do something
}
}
I am trying to keep vue instance's methods not to be crowded with a bunch of functions.
No, within the model you need features that are in this your component
soluction:
click.js
module.exports = {
executeClick: function () {
}
}
component.vue
<template>
<tag #click="$options.click.executeClick">
</template>
<script>
import click from 'click.js'
export default {
click: click
}
</script>

Call a VueJS method inside a component outside 'export default'

I'm trying to call a function inside 'method' from outside. However, it isn't working.
Github issue reporting the same: https://github.com/vuejs/vue/issues/329
vm.test(); // call a function in method, not working
this.vue.test() // not working
export default {
methods: {
test: function() {
alert('test fuction called');
}
}
}
It is not very clear what the actual goal of the original poster is, however this is how you can call a method on a Vue instance, after creating it:
var viewModel = new Vue({
el: "#app",
data: {
msg: "Hello there"
},
methods: {
test: function() {
alert('test fuction called');
}
}
});
viewModel.test();
Working example: https://jsfiddle.net/Daryn/Lja7pake/3/
If you are exporting a single file component then try this:
example.js
<script>
export default {
methods: {
test: function() {
alert('test fuction called');
}
}
}
</script>
main.js
<script>
import Thing from './example.js';
Thing.test();
</script>
Reference: https://v2.vuejs.org/v2/guide/single-file-components.html
What you are trying to achieve is fundamentally flawed. You can't call a method of a component unless you have a reference to an instance of that particular component. In your code, which particular component is vm referring to?
All you're doing is exporting a Vue component definition from your module; there's no component being instantiated here.
We'll need to see more of your code or a complete explanation of what exactly you're trying to achieve so we can provide an alternative solution. (Why are you trying to call the component's method outside of its definition?)
export default {
...
methods: {
...
},
mounted () {
EventBus.$on(‘EVENT_NAME’, function (payLoad) {
...
});
}
}
This is the way I solved that problem.
For the purpose of this demonstration, we create a new project using Vue/CLI. After installation finished, we make the vm exposed to global. Open src/main.js and edit like so:
src/main.js
import Vue from 'vue';
import App from './App.vue';
var vm = new Vue({
router,
render: h => h(App)
}).$mount('#app');
// Add this line (tambahkan baris berikut):
window.vm = vm;
Leave the generated App.vue like it is. So the first child of vm (vm.$children[0]) is App.vue.
We see that App.vue have a child. That makes HelloWorld.vue component as a grand children of vm (vm.$children[0].$children[0]). Knowing this, we can call the methods from outside 'export default' like this:
src/components/HelloWorld.vue
<template>
<div class="hello">
<button
id="sebuahButton"
class="btn btn-outline-secondary btn-sm"
type="button"
>Click Me, Jose!</button>
<h1>{{ msg }}</h1>
<!-- and some stuff, vue cli default generated code -->
<div>
</template>
<script>
(function() {
// wait for the DOM ready event in plain JavaScript
document.addEventListener("DOMContentLoaded", event => {
document.getElementById("sebuahButton").onclick = function() {
vm.$children[0].$children[0].someAction();
};
});
})();
export default {
name: "HelloWorld",
props: {
msg: String
}
methods: {
someAction () {
// do something (lakukan sesuatu masbro!)
console.log("It's been called from outer space, Luke!");
}
}
}
</script>