What is the best approach to create a form wizard with validation using Vue.js?

I recently completed a Vue.Js project where I created a wizard based on a video tutorial. However, I am facing issues with form validation using the 'is-valid' and 'is-invalid' CSS classes that I have defined. Here is my code:

<div class="modal-content tx-14">
              // Code for tabs and steps
           </div>

Javascript

    <script>
   new Vue({
       el: "#page",
       delimiters: ['[[', ']]'],
         data (){
            return {
               rules: {
                  project_url: {
                     pattern: /^(?:http(s)?:\/\/)?[\w.-]+(?:\.[\w\.-]+)+[\w\-\._~:/?#[\]@!\$&'\(\)\*\+,;=.]+$/,
                     string: ''
                  },
                  project_name: {
                     pattern: /^(?!\s*$).+/,
                     string: ''
                  }
               },
               current_step: 1,
               max_step: 1
            }
        },
        methods:{
            // Validation logic here
        }
    })
</script>

Looking for assistance to clean up my code and implement form validation properly.

Answer №1

The fundamental concept here is to focus on validating the data within a form, rather than the form itself.

Some may argue that "they are the same" or "it's a subtle distinction," but there is indeed a difference.

Instead of manipulating the form UI directly with jQuery, it is recommended to store form data in the data option of Vue and only display validation results.

Vue.component('InputField', {
  props: ['error', 'value'],
  computed: {
    inputValue: {
      get() {
        return this.value
      },
      set(val) {
        this.$emit("update:value", val)
      }
    },
  },
  template: `
    <div
      class="input-field-wrapper"
      :class="{ error: error }"
    >
      <label>
        INPUT: 
        <input
          type="text"
          placeholder="Type in something"
          v-model="inputValue"
        />
        <span v-if="error">this field is required!</span>
      </label>
    </div>
  `
})

new Vue({
  el: "#app",
  data() {
    return {
      form: [],
      canSubmit: false,
    }
  },
  methods: {
    handleAddInput(id) {
      this.form.push({
        id,
        error: null,
        value: null,
      })
    },
    handleFormValidate() {
      this.form = this.form.map(({ id, error, value }) => {
        return {
          id,
          error: !value,
          value,
        }
      })
      return this.form.every(({
        error
      }) => !error)
    },
    handleResetValidation() {
      this.form = this.form.map(field => {
        return {
          ...field,
          error: false
        }
      })
    },
    handleSubmitForm() {
      this.canSubmit = this.handleFormValidate()
    },
  },
  template: `
    <div>
      <button
        @click="handleAddInput(form.length + 1)"
      >ADD INPUT FIELD +</button>
      <button
        @click="handleFormValidate"
      >VALIDATE FORM</button>
      <button
        @click="handleResetValidation"
      >RESET VALIDATION</button>
      <hr />
      <form>
        <input-field
          v-for="(inputField, i) in form"
          :key="inputField.id"
          :error="inputField.error"
          :value.sync="inputField.value"
        ></input-field>
        <hr />
        <button type="submit" @click.prevent="handleSubmitForm">SUBMIT FORM</button>
      </form>
      FORM CAN BE SUBMITTED: {{ canSubmit }}
    </div>
  `
})
.input-field-wrapper {
  padding: 8px 16px;
  color: black;
}
.input-field-wrapper.error {
  color: white;
  background: red;
  transition: all 0.1s;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app"></div>

HOW IT OPERATES

The provided code snippet operates as follows:

  • It contains a data attribute (form) that stores all the data from the form along with the crucial error state
  • Upon clicking ADD INPUT FIELD +, a new object is added to the form attribute
  • The template generates an InputField component for each object found in the form data attribute
  • The InputField component primarily renders a text input element (with an error class if validation fails) and emits the input value back to the parent for storage in the form data
  • Clicking VALIDATE FORM iterates through the form data, checks the value of each element, sets the error if validation fails, and updates the
    :error="inputField.error"
    binding accordingly
  • Clicking SUBMIT FORM validates the form and outputs the validation result (acting as a guard before submitting the form)
  • Clicking RESET VALIDATION clears the error state of every item in the form array, resetting the error display in the InputFields component

This setup demonstrates that by adopting a "data-driven" approach, direct manipulation of the DOM is not always necessary (except for rare cases where avoiding it would require excessive effort). Decoupling data and UI provides more flexibility in designing the application logic without relying on jQuery.

You can achieve your goals without using jQuery.

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

Loading views and controllers on-the-fly in AngularJS

A new configuration tool is under development using Angular.JS. The user interface consists of two main sections: a left panel with a tree view listing all the configuration items and a right panel displaying screens for editing these items. There are appr ...

call a custom form submission using jquery first, followed by a regular form submission

Is it possible to attach a submit() handler to a form in order to execute an ajax request, and then have the form submit itself normally once the request is complete? Using $('#myForm').submit() seems to just result in the same function being cal ...

The state variables of React components do not always retain their most recent value

Currently, I am working on implementing the functionality of an event based library called powerbi-client-react. The first step involves retrieving the component using getEmbeddedComponent and storing it in the variable report. Then, I need to utilize the ...

The jQuery UI Dialog refuses to close

Dealing with a perplexing quandary involving jQuery UI Dialog. The default close button on the dialog doesn't seem to be functioning properly - however, an interesting workaround exists! Intriguingly, when clicking on the adjacent areas of the button, ...

Eliminate spaces within a string using JavaScript

In my quest for knowledge about trimming strings in JavaScript, I came across this intriguing discussion with a regex-based solution. After learning from the thread, I was under the assumption that trim would eliminate the space between "Hello" and "World ...

Error message: The "spawn" function is not defined and is causing a TypeError to be thrown in

Having a bit of trouble here. I'm trying to make an async request using redux-thunk in my action creator, and the code looks like this: export const downloadFromYoutube = (download) => { console.log("Hello"); return dispatch => { va ...

Experimenting with the input type generated by the Form Helper tool

Before generating the form using Form Helper, is there a method to preview the type of input it will produce? I would like to confirm whether it will result in a select or multi-select element before loading the page. ...

Mean Stack involves the interaction between the client controller and the server controller using routes to communicate and call server methods

I am currently developing a mean stack application and encountering difficulties when attempting to send requests to the Express/Node server in order to delete an element from an array in Mongo. Below is my schema for reference: var DeckSchema = new Schem ...

Creating a service function (constructor) in JavaScript

When working with AngularJs and calling a service method: app.service('nameService', function() { this.Service = function (){console.log('hello')} } You can then use this service (object) like so: nameService.Service() My question is, ...

Incapable of retrieving data from MongoDB due to a failure in fetching results using streams in Highland.js

I have recently started working with streams and I am experimenting with fetching data from my collection using reactive-superglue/highland.js (https://github.com/santillaner/reactive-superglue). var sg = require("reactive-superglue") var query = sg.mong ...

Positioning Images in Tailwind Modals

I'm currently working on building a modal using Tailwind in Vue, but I've run into some challenges with aligning the elements inside the modal as desired. I've experimented with removing certain Tailwind classes and have tried implementing ...

Issues arise when attempting to extract data from a data provider using JSON within the context of the Ionic framework

Hey there! I'm relatively new to the world of Angular and Ionic, and I've embarked on a project to create a pokedex app. My approach involves using a JSON file containing an array of "pocket monsters". However, my current challenge lies in extrac ...

Using the useState hook with an array of objects is not functioning as intended

I have initialized a useState object in my file like this: const [comments, setComments] = useState({ step_up: [], toe_walking: [], toe_touches: [], squat: [], side_to_side: [], rolling: [], leg_lifts: [], hand_to_knees: [], floo ...

Is there a way to determine the orientation of an image in React-Native, whether it is horizontal or vertical

When working with react-native, I aim to utilize the 'contain' feature for vertical images and the 'stretch' feature for horizontal images. What would be the best way to determine the orientation of an image as either horizontal or vert ...

A guide to implementing v-for with intervals in Quasar carousel components

I need help making my blog summary page more dynamic by using a q-carousel to display 3 blog posts per slide. I want to create an array with all the blog posts and loop through it with v-for to populate each slide dynamically while keeping the pagination l ...

Rails, implementing a user-friendly form with Simple Form and a dynamic show/hide functionality

Utilizing simple form within my Rails 4 application. I have separate models for projects, scopes, and data. The projects model accepts nested attributes for scopes, while scopes accept nested attributes for data. In the new project form, I include a que ...

Is there a way to use Javascript to determine if a string within a JSON object has been altered?

I am looking for a way to continuously monitor changes in a specific string or date stored in a JSON file. How can I effectively store this value and create a mechanism to compare it for any differences? Any assistance would be highly appreciated. // Ex ...

Can someone help me with combining these two HTML and JavaScript files?

I successfully created an HTML/JavaScript file that functions properly: <html> <head> <meta name="viewport" content="initial-scale=1.0, user-scalable=no" /> <script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor ...

Is employing absolute paths in our confidential Node dependencies a good idea?

I have recently organized our codebase's React components into a separate dependency to make them reusable across different projects. To improve readability, all components now utilize Webpack aliases: import TestComponent from 'components/TestCo ...

My Angular2+ application is encountering errors with all components and modules displaying the message "Provider for Router not found."

After adding routing to my basic app through app.routing.ts, I encountered errors in all of my test files stating that no Router is provided. To resolve the errors, I found that I can add imports: [RouterTestingModule], but is there a way to globally impo ...