Ensure the validation of numerous input fields within a single form with the use of Vue 3 composition API

Within my application, I have implemented custom validation and validators to ensure the accuracy of various form fields. The submit button functionality is designed to remain disabled until all input fields are filled.

The creation of validators involves defining rules as shown below:

// validator.js

export default function validators() {
      const isEmpty = (fieldName, fieldValue) => (!fieldValue ? `The ${fieldName} field cannot be empty` : '');
      const minLength = (fieldName, fieldValue, min) => (fieldValue.length < min ? `The ${fieldName} must contain at least ${min} characters` : '');
      return {
        isEmpty,
        minLength,
      };
    }

These validators are then incorporated into the validation logic for various input types such as text areas and emails, as illustrated in the example below:

// formValidation
import { reactive } from 'vue';
import Validators from './validators';

const errors = reactive({});
const {
  minLength, isEmpty
} = Validators();
export default function formValidation() {
  const validateInputField = (fieldName, fieldValue) => {
    errors[fieldName] = !fieldValue
      ? isEmpty(fieldName, fieldValue) : minLength(fieldName, fieldValue, 2);
  };
  return {
    errors,
    validateInputField,
  };
}

Furthermore, a custom button validation state has been created using a computed property:

Button State

import { computed } from 'vue';

export default function submitButtonState(field, errors) {
  const isButtonDisabled = computed(() => {
    let disabled = true;
    for (const prop in field) {
      if (Object.hasOwn(field, prop)) {
        if (!field[prop] || errors[prop]) {
          disabled = true;
          break;
        }
        disabled = false;
      }
    }
    return disabled;
  });
  return {
    isButtonDisabled,
  };
}

In my component, I am utilizing pinia store to store all input variables. While input storage functions correctly, the button state always remains disabled and fails to update accordingly.

Below is the code snippet of the component:

<template>
 <div> 
  <span>Form Description</span>
  <p>
  <my-textarea
        :message-type="errors.address ? 'negative' : ''"
        :validation-message ="errors.address"
        max-length="100"
      >
    <textarea
      v-model="formResponses.txtArea1"
      @blur="validate1stInput"
      @keypress="validate1stInput"
      slot="textarea"
      maxlength="100"
    ></textarea>
    <label slot="label" for="textarea">Address</label>
   </my-textarea>
  </p>
  <p>
  <my-textarea
        :message-type="errors.comments? 'negative' : ''"
        :validation-message ="errors.comments"
        max-length="100"
      >
    <textarea
      v-model="formResponses.txtArea2"
      @blur="validate1stInput2"
      @keypress="validate1stInput2"
      slot="textarea"
      maxlength="100"
    ></textarea>
    <label slot="label" for="textarea">Comments</label>
   </my-textarea>
  </p>
  <p><button class="myButton" @click.prevent="submit" :disabled="isButtonDisabled"></button></p>
 </div>
</template>

<script setup>
import UserStore from '@/store/userStore';  
import FormValidation from '@/utilities/useFormValidation';
import SubmitButtonState from '@/utilities/SubmitButtonState';
import { ref, reactive, watch } from 'vue';
import { storeToRefs } from 'pinia';

const { form1 } = storeToRefs(UserStore());
const formResponses = reactive({ ...form1.value });

const { validateInputField, errors } = FormValidation();

const { isButtonDisabled } = SubmitButtonState(formResponses, errors); 

const validate1stInput = () => {
  validateInputField('address', formResponses.txtArea1);
};
const validate1stInput2 = () => {
  validateInputField('comments', formResponses.txtArea2);
};

watch(() => errors, { immediate: true });

</script>

The current issue lies in the button state not updating due to the error states not being updated. This poses a challenge when dealing with multiple inputs. To address this, it's essential to debug and identify the root cause of the disabled button state persisting even after correct input values are provided.

For reference, you can access the working codesandbox here:

View Codesandbox

Answer №1

In order to monitor the state change, it's important to utilize a computed property as shown in this TypeScript example:

const isSubmitButtonDisabled: ComputedRef<boolean> = computed((): boolean => checkIfButtonShouldBeDisabled(formResponses, errors));

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

Using jQuery functions to disable adding or removing classes with a click event

Has anyone had success implementing a functionality where a div expands upon clicking, and reverts back to its original state when clicking on a cancel link within the same div? <div class="new-discussion small"> <a class="cancel">Cancel&l ...

Error: jQuery Validation not triggering in Bootstrap modal window

My attempts to use jQuery Validation for form validation inside a modal have hit a dead end. The validation doesn't trigger at all, not even an error message is displayed. Upon debugging, a warning emerged: No elements selected for validation; retu ...

Next.js pages do not respond to event listeners

Something strange is happening in my Next.js project. I've implemented a header that changes color as the page scrolls using the useEffect hook: The hook in the Header component looks like this: React.useEffect(() => { window.addEventListener(&a ...

Strategies for smoothly navigating the page to a specific div every time

Currently, I am working on a form that requires submitting multiple child forms. To enhance user experience, I have incorporated jQuery functionality to display a message at the top of the page upon each submission. Now, my goal is to implement a feature w ...

Unable to retrieve obj after using $location.url

I am working with two different views. In the first view, I call a function from the admin controller using AngularJS: <a ng-click="updateAdmin(admin)">update</a> The code in the admin controller looks like this: $scope.updateAdmin = functio ...

"When I use breakpoints and run my application in debugging mode, it performs flawlessly. However, without these tools, it

I have developed an application using the Ionic Framework with Firebase as the backend. When I run the application with breakpoints using the debugger, everything works fine. However, if I run it without the debugger, I notice that values are not being upd ...

Having difficulty uploading an image to Facebook through the graph API

I have a requirement to upload a photo to Facebook using the Javascript SDK, but I am experiencing some difficulties: Firstly, FB.login(function (response) { if (response.authResponse) { va ...

Learn to save Canvas graphics as an image file with the powerful combination of fabric.js and React

I am currently utilizing fabric.js in a React application. I encountered an issue while attempting to export the entire canvas as an image, outlined below: The canvas resets after clicking the export button. When zoomed or panned, I am unable to export co ...

How can I use jQuery to target and modify multiple elements simultaneously

I've been struggling for the past couple of hours trying to use prop to change the values of two items in a button. One item updates successfully, but the other one doesn't and I can't figure out why. Here is the HTML: <input type=&apos ...

What is the best way to specify svg attributes in virtual-dom?

Can attributes be added to SVG nodes using virtual-hyperscript in a virtual dom? Like this: var h = require('virtual-dom/h') h('svg', [ h('circle', {cx: 100, cy: 100}, 'some text') ]) I attempted this but the ...

Troubleshooting Vue.js 2 Routing Issues: Difficulty Accessing Posts Variable

My first venture into Vue.js involves working with WP REST API. Initially, all my posts are displayed perfectly. However, when I attempt to integrate Vue-router, the component responsible for showcasing all the posts, 'home-post-list', breaks do ...

Exploring creative methods for incorporating images in checkboxes with CSS or potentially JavaScript

Although it may seem like a basic question, I have never encountered this particular task before. My designer is requesting something similar to this design for checkboxes (positioned on the left side with grey for checked boxes and white for unchecked). ...

How do I remove the scroll bar from the datagrid using Material UI?

https://i.stack.imgur.com/lM01l.png Is there a way to remove the scroll bar at the bottom of the page? I have already attempted using autoPageSize, but it did not solve the issue. Here is the link to the autoPageSize documentation. import { DataGrid } f ...

Dropdown menu of countries created with Material UI

I have been working on creating a dropdown menu in my form that lists all countries. I used an Array of strings with country names and mapped through it to generate the options for the select dropdown. However, the dropdown menu does not seem to be worki ...

"PHP script for submitting a form with a post button

Can anyone help me figure out why the submit function isn't working? I've been trying to solve the problem with no luck so far. Any ideas on what might be causing this issue? <?php if(isset($_POST['submit'])){ echo ("Submit fun ...

Change elements in real-time

I have a requirement to adjust elements with the class .super-elem by adding an attribute adjusted="true". Initially, I can easily achieve this within the document's ready event : $(".super-elem").attr("adjusted", "true"); However, I may add more . ...

Steps for referencing a custom JavaScript file instead of the default one:

Currently, I am utilizing webpack and typescript in my single page application in combination with the oidc-client npm package. The structure of the oidc-client package that I am working with is as follows: oidc-client.d.ts oidc-client.js oidc-client.rs ...

Problem with targeting the .prev() and closest() class of a text input box

Could you please review This Demo and advise why I am unable to select the first .fa class before the text box #name ? This is what I have been trying: $(this).prev().closest(".fa").addClass("err"); within this code block <div class="row"> & ...

Incorporating JavaScript to dynamically load an HTML page into an iframe

I am attempting to have each option load a unique page within a frame <!DOCTYPE html> <html> <head> <script> function selectCountry() { var mylist=document.getElementById("country"); document.getElementById("frame").src=mylist.opti ...

incorporating theme.spacing in the declaration of the theme

The theme setup that I am working with is as follows: export const themeDefault = createTheme({ themeName: 'Default (Mortgage Hub)', spacing: 4, ...typography, palette, components: { MuiButton: { styleOverrides: { root ...