What is the best way to interact with native HTML elements within the template of a functional component in Vue.js?

Looking to develop a customized checkbox component using Vue.js 2.6 that remains stateless, receiving its value as a prop and emitting an event to the parent component upon user input without storing any data internally.

Here is the simplified single-file component:

<script lang="ts">
import Vue from 'vue';

export default Vue.extend({
  functional: true,
  props: {
    value: {
      type: Boolean,
      default: false,
    },
  },
});
</script>
<template functional lang="pug">
label
  input(type="checkbox" :checked="value" ref="input"
    @input="(listeners['input'] || (() => {}))($event.target.checked)")
</template>

This generates the following render function:

var render = function(_h, _vm) {
  var _c = _vm._c
  return _c("label", [
    _c("input", {
      ref: "input",
      attrs: { type: "checkbox" },
      domProps: { checked: _vm.value },
      on: {
        input: (_vm.listeners["input"] || function() {})(
          _vm.$event.target.checked // Issue occurs here
        )
      }
    })
  ])
}
var staticRenderFns = []
render._withStripped = true

Parent component:

<template lang="pug">
form
  checkbox(:value="value" @input="value = $event")
</template>
<script lang="ts">
import Vue from 'vue';
import { default as Checkbox } from './checkbox.vue';

export default Vue.extend({
  components: {
    checkbox: Checkbox,
  },
  data() {
    return { value: false };
  },
});
</script>

When dealing with the native input element to trigger the input event, I aim to pass the checked property of the input to the parent listener (if it exists).

I've attempted using $event.target.checked and $refs.input.checked in the event handler for this purpose but faced limitations due to not having direct access within a functional template:

TypeError: "_vm.$refs is undefined"

Is there a workaround to access the native HTML element triggering an event within the attached event handler of a functional component template? Alternatively, should I resort to utilizing a stateful component in such cases?

Answer №1

Yes, you can make it work, but not in the typical way you might expect. The unique behavior of functional components is that they pass their refs up the tree. This means that your ref 'input' will actually appear in the component that includes your functional checkbox, rather than within the checkbox itself. If you attempt to attach a ref directly to your functional component using a template, it will fail.

For example, the following scenario would not function as intended (in your parent component) because ref 'check' will not be present. However, ref 'input' will be available, at least the last one added if multiple checkboxes are used:

<form>
    <functional-checkbox ref="check" :value="myValue" @input="myValue = $event"/>
</form>

On the other hand, this approach will work properly:

<form>
    <functional-checkbox :value="myValue" @input="myValue = $event"/>
</form>

// later in code assuming that functional-checkbox has ref="input" defined inside
this.$refs.input // will contain a value when the component is mounted

If you're facing issues with a functional checkbox component, there's a simpler workaround available. You just need to structure your handler as a function call that aligns with how the Vue template compiler processes it. Despite creating a function call, it may not be interpreted correctly, leading to potential errors.

To simplify your function call effectively, consider making adjustments like so:

<template functional>
    <label>
        <input type="checkbox" :checked="props.value"
               @input="listeners.input && listeners.input($event.target.checked)">
    </label>
</template>

With this modification, your code should be processed as intended:

var render = function(_h, _vm) {
  var _c = _vm._c
  return _c("label", [
    _c("input", {
      attrs: { type: "checkbox" },
      domProps: { checked: _vm.props.value },
      on: {
        input: function($event) {
          _vm.listeners.input && _vm.listeners.input($event.target.checked)
        }
      }
    })
  ])
}

If you're curious about how this render function is generated, you can explore more details here: https://github.com/vuejs/vue/blob/dev/packages/vue-template-compiler/browser.js#L4169

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Hmm, JavaScript is throwing a JSON parse error related to single quotes. But where exactly is

When using an upload php script with AS3 and now with JavaScript, I encountered a test feature that should return this if everything is okay: {"erro":"OK","msg":"","descr":"op:ini,urlArq:\/Library\/WebServer\/Documents\/www\/sintr ...

Unable to transfer the component between components

This is the code I have: index.js: import React from "react"; import ReactDOM from "react-dom"; import {dest, People} from './components/people'; import json from './people.json'; function initFromJson() { let names = []; for(let ...

Leveraging the power of cannon.js for detecting collisions within a three.js gaming environment

Trying to figure out a way to handle collisions between objects in my three.js project. Considering using cannon.js for its support of necessary primitives, but don't always need all the physics overhead, just collision detection in many cases. Don&ap ...

Is it possible for me to use jQuery to apply e.preventDefault() to all links within my code?

Curious about this issue: In my HTML file, I have several links where I need to prevent them from jumping to the top of the page in their click functions. The action of preventing the default behavior (e.preventDefault()) needs to be added separately from ...

The PHP blocking code in Zend Server not only blocks the response of the current ajax call but also impacts the handling

I encountered a peculiar problem. Suppose I have an ajax call like this; $.ajax({ url:"url1.php", }) Following this ajax call, I have another ajax call as follows; $.ajax({ url:"url2.php", success:function(data){console.log(data);} }) ...

can a computed property be delayed in its calculation?

Within the code snippet below, we can see that in the compPropsIsBtnDigitizePolygonDisabled function, it initially checks if the digitizePolygonInteractions variable is initialized. If it is not initialized, an error will be triggered. During execution, w ...

A gathering focused on the pause function of a bootstrap carousel

After carefully reviewing the documentation, it seems there isn't a specific event to detect when the carousel is paused. Is there a workaround for detecting when the bootstrap carousel is paused? The carousel can be paused using various methods, and ...

Whenever I press a button, my desire is for each picture to seamlessly reposition itself in the exact same spot on the screen

Having some issues with my code. When I click a button, the plan is for the pictures to change one by one to simulate a traffic light sequence. However, when I run the code, all the pictures appear at once without any effect from the button. Any help in ac ...

Getting an array of objects that have been sent via Ajax in Laravel can be achieved by accessing the

Currently, my setup involves using Laravel alongside Vuejs and AXIOS for handling HTTP requests. I'm faced with a challenge when sending a post request containing an array of objects. The question now is, how can I extract and work with this data in m ...

Enhancing Form Validation with Jquery: SSN Pattern Matching, Input Masking, and Conditional Validation

Struggling with getting the Jquery Validation to cooperate with specific rules. The SSN field is masked with SSN format, and I need the validation to prevent submission unless it's a complete SSN. There's a regex function that rejects non-SSNs, ...

When scrolling, apply a CSS class to a div element once it becomes visible on the

I'm in the process of developing a timeline feature for my website, and I am facing an issue where the addClass function is being applied to all sections, even those that are not currently visible on the screen during scrolling. If you would like to ...

Forwarding users to a new destination through a script embedded within a frame

Currently, I am facing an issue where a page (lobby_box.php) is being loaded every 4 seconds on my main page (index.php) using JavaScript. The problem arises when the code within (lobby_box.php) that is meant to redirect the client from index.php to anothe ...

LESS: Using variable values in mixin and variable names

I am looking to simplify the process of generating icons from svg-files while also creating a png-sprite fallback for IE8 support. I am using grunt.js and less. I was inspired by the implementation on 2gis.ru: (in Russian), where they used technologies s ...

Enhancing user experience with scroll snapping within nested components/elements

https://i.sstatic.net/PzNmP.gif Looking at the gif, you can see a large scrollable container with various main blocks ('Attack', 'Release', etc.) housed within it. Each main block contains one or multiple columns (such as 'Attack ...

Working solely with CDNs, harness Vuetify alongside i18n for enhanced features

Currently, I am developing a Vue project within a static environment that lacks Node or Vue-cli support. In order to utilize Vue, Vuetify, and vue-i18n, we are incorporating them through CDNs. Our goal is to translate the Vuetify components using Vue-i18n ...

Error encountered while parsing data in Internet Explorer versions 7, 8, 9, and 10 due to an invalid character. The status

This block of code is functioning correctly on Chrome and Firefox, however it seems to be having issues with Internet Explorer! It involves a simple JSON file call, fetching data, and then displaying it on an HTML webpage. Here's the code snippet: $. ...

When React-select is toggled, it displays the keyboard

While using react-select ^1.2.1, I have come across a strange issue. Whenever I toggle the drop-down in mobile view, the keyboard pops up unexpectedly as shown in this screenshot https://i.stack.imgur.com/mkZDZ.png The component code is as follows: rende ...

Submit a collection of images and an object to the server using ReactJS

I'm currently working with Reactjs on the frontend. In order to set the profile picture to state, I've implemented the following code: handleImageChange = (event) => { event.preventDefault(); var file = event.target.files[ ...

Removing a Child Object from a JSON Object in AngularJS

Encountering an error while attempting to remove a Child object Error Message: TypeError: ctrl.otsact.tests.splice is not a function HTML : <tr ng-repeat="act in ctrl.otsact.tests" ng-if="ctrl.editToggle"> <td><span ng-click="ctrl.r ...

Customize your payment with a PayPal button tailored to your desired price

I've been tasked with creating a dynamic PayPal button that can receive different values based on user choices. The website has so many options that creating separate buttons for each choice doesn't seem feasible. I've tried researching solu ...