Randy Hall
Randy Hall

Reputation: 8167

Pass events onto an element of component VueJS

I have some component that wraps up an input:

<div class="some-component">
    <input type="text" />
</div>

And I'm calling it like so:

<some-component v-on:click="dostuff" ref="thatcomponent"></some-component>

And then:

methods: {
    dostuff(){
        this.$refs.thatcomponent.$el.focus();
    }
}

Which focuses the div, where I really want focus to be on the input. This example is my first use-case, but in general I want to pass all the events called on the component to a specific element within that component. I don't want to go poking around in the component for the element from the parent component.

Is there a Vue pattern for this?

Upvotes: 1

Views: 1849

Answers (3)

Youssef BH
Youssef BH

Reputation: 582

I guess your best bet here is using ref attribute and $refs object. This section in Vuejs Docs might be useful.

Child Component

in template:

<div class="some-component">
  <input ref="input" type="text" />
</div>

in script:

methods: {
  ...
  focus() {
    this.$refs.input.focus();
  },
  ...
},

Parent Component

in template:

You need here to use the .native modifier to listen directly to a native event on the root element.

<some-component v-on:click.native="dostuff" ref="thatcomponent"></some-component>

in script:

methods: {
  ...
  dostuff() {
    this.$refs.thatcomponent.focus();
  },
  ...
}

Vuejs Docs

$refs are only populated after the component has been rendered, and they are not reactive. It is only meant as an escape hatch for direct child manipulation - you should avoid accessing $refs from within templates or computed properties.

Here is CodeSandBox example

I Hope this help.

Upvotes: 0

safrazik
safrazik

Reputation: 1601

Better approach is to add the focus method within the child-component

child-component

<div class="child-component">
    <input type="text" ref="theInput" />
</div>
// child-component
methods: {
    focus(){
        this.$refs.theInput.focus();
    }
}

parent-component

<child-component v-on:click="dostuff" ref="childComponent"></child-component>
// parent-component
methods: {
    dostuff(){
        this.$refs.childComponent.focus();
    }
}

In any case if you want to interact with the child-component's input element from parent-component (useful if you don't have control over the child-component

// parent-component
methods: {
    dostuff(){
        this.$refs.childComponent.$el.querySelector('input').focus();
    }
}

Upvotes: 2

TommyF
TommyF

Reputation: 7160

I'm not aware of a Vue specific solution to this. You can however manually redirect an event from one element to another by dispatching a new event on the target element.
You will however need a reference to the target element as well as handling all event types manually (there is no wildcard event listener like foo.addEventListener("*", ...)

clicked(e) {
  var target = document.querySelector("#target");
  target.dispatchEvent(new event.constructor(e.type, e));
}

Basic example:
https://codesandbox.io/s/vue-template-76svb

It is a very unusual pattern though and one should carefully evaluate if this is the correct solution to the problem.

Upvotes: 1

Related Questions