0
votes

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()
            }
        })
    }
}
2
Your overriding function must be bound to the child instance - or otherwise it can not use the this reference. It will be easier and cleaner if the method in your child accepts an argument of type Function - then you can provide a method from the parent as argument to the child's method.IVO GELOV

2 Answers

0
votes

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')
        }
  }
}
0
votes

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
        })
    }
}