Categories
React Vue

React vs Vue — Handling Selections

React is the most popular front end library for the last few years. Vue is a front end framework that’s catching up quickly.

It’s hard to choose between the 2 frameworks since they both have their pros and cons.

In this article, we’ll compare how React and Vue frameworks handle form radio button and drop-down selections and which one is easier for developers.

Radio Buttons

With Vue, we can use the v-model directive to bind the radio button choices to the component’s model directly.

For example, with Vue, we write the following to add a set of radio buttons and display the selected choice on the screen:

index.html :

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  </head>
  <body>
    <div id="app">
      <input type="radio" value="One" v-model="picked" />
      <label>One</label>
      <br />
      <input type="radio" value="Two" v-model="picked" />
      <label>Two</label>
      <br />
      <span>Picked: {{ picked }}</span>
    </div>
    <script src="index.js"></script>
  </body>
</html>

index.js :

const app = new Vue({
  el: "#app",
  data: {
    picked: ""
  }
});

In the code above, we just set the value of v-model of both radio buttons to the same picked model.

Then when we click either radio button, we’ll see the selected choice show in the span.

With React, we have to add the checked prop to each radio button so that only the value that’s selected is checked.

For instance, we write the following to rewrite the example above with React:

import React, { useState } from "react";

export default function App() {
  const [picked, setPicked] = useState("");
  const handleClick = e => setPicked(e.target.value);

  return (
    <div className="App">
      <input
        type="radio"
        value="One"
        checked={picked === "One"}
        onClick={handleClick}
      />
      <label>One</label>
      <br />
      <input
        type="radio"
        value="Two"
        checked={picked === "Two"}
        onClick={handleClick}
      />
      <label>Two</label>
      <br />
      <span>Picked: {picked}</span>
    </div>
  );
}

In the code above, we have the same 2 radio buttons as in the Vue example, but we added a onClick handler to set the picked state, and we also have the checked attribute to indicate when they should be checked.

We indicate that we only want them selected when the given value is picked.

This is extra work that we don’t have to with Vue.

Handling Drop-Down Selections

We can use v-model to bind directly to the selected value of the dropdown with Vue.

Therefore, we can write the following to create a drop-down and then display the selected choice:

index.html :

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  </head>
  <body>
    <div id="app">
      <select v-model="picked">
        <option>One</option>
        <option>Two</option>
      </select>
      <br />
      <span>Picked: {{ picked }}</span>
    </div>
    <script src="index.js"></script>
  </body>
</html>

index.js :

const app = new Vue({
  el: "#app",
  data: {
    picked: ""
  }
});

In the code above, we created a dropdown and then bind the selected value to the picked model in the Vue component.

Then we referenced picked to display the selected choice in the span.

We didn’t have to specify the value if the value and the displayed text are the same.

With React, we write the following code to handle setting the selected value from a dropdown:

import React, { useState } from "react";

export default function App() {
  const [picked, setPicked] = useState("");

  return (
    <div className="App">
      <select onChange={e => setPicked(e.target.value)}>
        <option>One</option>
        <option>Two</option>
      </select>
      <br />
      <span>Picked: {picked}</span>
    </div>
  );
}

To handle change in the value of a dropdown, we pass in an event handler to set the selected value to the picked state.

Then we display it in the span below the dropdown.

The Vue and React examples are pretty close with respect to handling dropdowns.

Multiple Selections

With Vue, it’s easy to handle the values of select elements that let users select multiple values.

We can write the following code to do that:

index.html :

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  </head>
  <body>
    <div id="app">
      <select v-model="picked" multiple>
        <option>One</option>
        <option>Two</option>
        <option>Three</option>
      </select>
      <br />
      <span>Picked: {{ picked }}</span>
    </div>
    <script src="index.js"></script>
  </body>
</html>

index.js :

const app = new Vue({
  el: "#app",
  data: {
    picked: []
  }
});

In the code above, we have a select element with the multiple attribute to enable multiple selection.

Then we just bind to the picked array with v-model and reference the picked array straight in the template to display the selected choices.

With React, we have to write the following to get the selected choices and display them:

import React, { useState } from "react";

export default function App() {
  const [picked, setPicked] = useState([]);

  return (
    <div className="App">
      <select
        multiple
        onChange={e =>
          setPicked([...e.target.selectedOptions].map(o => o.value))
        }
      >
        <option>One</option>
        <option>Two</option>
        <option>Three</option>
      </select>
      <br />
      <span>Picked: {picked.join(", ")}</span>
    </div>
  );
}

In the code, we reference:

[...e.target.selectedOptions].map(o => o.value)

to get the selected options from the select element and then get the value property of each entry and put them in the picked array.

Then we display the picked entries by call join to combine the choices into one string.

As we can see, we have to do lots of things that we didn’t have to do in the Vue example to get equivalent functionality.

There’s way more logic involved just to get the selections from a select element that lets the user choose multiple choices.

Also, we have to spread the e.target.selectedOptions object so that we convert it to an array. e.target.selectedOptions is an array-like object, which isn’t an array.

Verdict

Vue is definitely better with handling radio buttons and select elements that let us choose multiple choices.

The v-model directive took care of most of the hard work of extracting the selected choices and displaying the data.

With React, we have to write our own code to extract the selected choices and display them also takes some work.

Categories
React Vue

React vs Vue — Handling Form Input

React is the most popular front end library for the last few years.

Vue is a front end framework that’s catching up in popularity with React in the last few years.

It’s hard to choose between the 2 frameworks since they both their pros and cons. When we choose one, we’ve to stick with it for a few years.

In this article, we’ll look at how we handle form input with React and Vue and which is better for developers.

Handling Form Input Values.

To handle form values with React, we have to add a onChange handler in each input to set the value of the input in the state.

For example, if we have multiple inputs in our form, then we have to write the following code to do that:

import React, { useState } from "react";

export default function App() {
  const [person, setPerson] = useState({});
  const onSubmit = e => {
    e.preventDefault();
    alert(`${person.firstName} ${person.lastName}`);
  };

  return (
    <div className="App">
      <form onSubmit={onSubmit}>
        <input
          name="firstName"
          placeholder="First Name"
          onChange={e => setPerson({ ...person, firstName: e.target.value })}
        />
        <br />
        <input
          name="lastName"
          placeholder="Last Name"
          onChange={e => setPerson({ ...person, lastName: e.target.value })}
        />
        <br />
        <input type="submit" value="Submit" />
      </form>
    </div>
  );
}

In the code above, we have 2 inputs with onChange handlers added to both to put the value that’s entered into the person object.

Then we update the value by calling setPerson with the object.

Once we did that, we can get the latest value of person in our onSubmit handler once we click Submit.

With all the onChange handlers we have to add, it definitely gets tedious when our for has lots of inputs.

The Vue equivalent of the code above would be the following:

index.html :

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  </head>
  <body>
    <div id="app">
      <form @submit.prevent="onSubmit">
        <input
          name="firstName"
          placeholder="First Name"
          v-model="person.firstName"
        />
        <br />
        <input
          name="firstName"
          placeholder="Last Name"
          v-model="person.lastName"
        />
        <br />
        <input type="submit" value="Submit" />
      </form>
    </div>
    <script src="index.js"></script>
  </body>
</html>

index.js :

const app = new Vue({
  el: "#app",
  data: {
    person: {
      firstName: "",
      lastName: ""
    }
  },
  methods: {
    onSubmit() {
      alert(`${this.person.firstName} ${this.person.lastName}`);
    }
  }
});

The Vue has the same form, but we can bind the input value to our Vue’s data value by using the v-model directive.

This is shorter than adding an onChange handler to every input that we have in our form.

Also, to call preventDefault , we can just write: .prevent instead of calling it explicitly, which is a nice shortcut that’s not available in React.

Handling form input is definitely cleaner with Vue than with React.

Handling Checkboxes

We can bind our checkbox choices to the Vue component’s model by setting the v-model directive to the same array.

For example, we can write the following code to do that:

index.html :

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  </head>
  <body>
    <div id="app">
      <input type="checkbox" value="Jane" v-model="checkedNames" />
      <label>Jack</label>
      <input type="checkbox" value="Mary" v-model="checkedNames" />
      <label>John</label>
      <input type="checkbox" value="Mike" v-model="checkedNames" />
      <label>Mike</label>
      <br />
      <span>Checked names: {{ checkedNames }}</span>
    </div>
    <script src="index.js"></script>
  </body>
</html>

index.js :

const app = new Vue({
  el: "#app",
  data: {
    checkedNames: []
  }
});

As we can see, we just have to declare the checkNames model in the data object and then we just set the value of v-model to checkedNames to get all the values that are checked.

With React, we have to update the value of each checkbox with an onChange handler that combines the old values with the new values, then we display the checked values by filtering out the ones that aren’t checked.

We write the following to do that:

import React, { useState } from "react";

export default function App() {
  const [checkedNames, setCheckedNames] = useState({});
  const handleCheck = e =>
    setCheckedNames({
      ...checkedNames,
      [e.target.value]: e.target.checked
    });

  return (
    <div className="App">
      <input type="checkbox" value="Jane" onChange={handleCheck} />
      <label>Jack</label>
      <input type="checkbox" value="Mary" onChange={handleCheck} />
      <label>John</label>
      <input type="checkbox" value="Mike" onChange={handleCheck} />
      <label>Mike</label>
      <br />
      <span>
        Checked names:{" "}
        {Object.keys(checkedNames)
          .filter(name => checkedNames[name])
          .join(", ")}
      </span>
    </div>
  );
}

In the code above, we created a handleCheck function to combine the existing checkbox entries, which has the value of the checkbox as the key and the checked value of each checkbox as the value.

Then to display the values that are checked, we have to filter out the ones that aren’t checked and then convert the resulting array to a string.

This is definitely much more work than just binding the values to v-model and then displaying an array as-is on the template in the Vue version.

Verdict

Vue’s v-model really takes the hard work out of form handling. Text input is easy to handle, and checkboxes are even more so.

To handle form values with React, we need onChange handlers for every input.

As we can see, if handling the value of a simple set of checkboxes is so complex with React, then if we have more inputs in a form, then it’s going to get even more complex.

We have to add a few lines of code just to display the checked values in the React example, which isn’t ideal.

Categories
React Vue

React vs Vue — Setting Attributes and Displaying Collections

React has been the most popular front end library for the last few years.

Vue is a front end framework that’s catching up in popularity with React and has an incredibly passionate developer community adopting it.

It’s hard to choose between the 2 frameworks since they both have their pros and cons. When we choose one, we’ve to stick with it for a few years.

In this article, we’ll look compare the setting attribute and displaying collections with React and Vue.

Setting Attributes

With React, we can set attributes like HTML. But we can also set dynamic attributes in our app.

For example, we can write the following code to do that:

import React, { useState } from "react";

export default function App() {
  const [color, setColor] = useState("red");
  const toggleColor = () => {
    setColor(color === "red" ? "green" : "red");
  };

  return (
    <div className="App">
      <button onClick={toggleColor}>Toggle</button>
      <div className="box" style={{ color }}>
        foo
      </div>
    </div>
  );
}

In the code above, we set the color of the div dynamically with the useState hook, which returns the setColor function to let us set the color.

Then we pass in the color to the style attribute. To set a static class name for our div, we have to use the className attribute. We have to remember differences like className instead of class when we set attributes with React.

With Vue, we put our data and methods in the component and set the static and dynamic attributes as follows:

index.html:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  </head>
  <body>
    <div id="app">
      <button @click="toggleColor">Toggle</button>
      <div class="box" :style="{color: color}">
        foo
      </div>
    </div>
    <script src="index.js"></script>
  </body>
</html>

index.js:

const app = new Vue({
  el: "#app",
  data: {
    color: "red"
  },
  methods: {
    toggleColor() {
      this.color = this.color === "red" ? "green" : "red";
    }
  }
});

With Vue, we have to add the toggleColor method to the method and a default value for the color field in the data object.

Then we have to add the same logic for setting the color in the toggleColor method.

This is more complex than what we have with React. However, it does separate the logic for display and business logic into separate parts.

This is easier to deal with when our components are more complex.

Displaying Collections

We can display collections with React by mapping our arrays to a collection of components.

For example, if we have an array of names, we can write the following to display them with React:

import React, { useState } from "react";

export default function App() {
  const [persons] = useState([
    { name: "Mary" },
    { name: "John" },
    { name: "Joe" }
  ]);

  return (
    <div className="App">
      {persons.map(p => (
        <div>{p.name}</div>
      ))}
    </div>
  );
}

In the code above, we have the persons array, which is then mapped to divs with p.name as the text content.

To do the same thing with Vue, we can write the following:

index.html:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  </head>
  <body>
    <div id="app">
      <div v-for="p of persons">
        {{p.name}}
      </div>
    </div>
    <script src="index.js"></script>
  </body>
</html>

index.js:

const app = new Vue({
  el: "#app",
  data: {
    persons: [{ name: "Mary" }, { name: "John" }, { name: "Joe" }]
  }
});

In the code above, we have the persons array in the Vue component, and the v-for directive to display items in the persons array.

This is cleaner than what we have with React. We keep the code in each file more compact.

This will be even more apparent is more components are more complex, which is often the case.

Another good thing about v-for is that we can use them to iterate through entries of an object as well.

For example, we can write the following to do that:

index.html:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  </head>
  <body>
    <div id="app">
      <div v-for="(age, name) in persons">
        {{name}}: {{age}}
      </div>
    </div>
    <script src="index.js"></script>
  </body>
</html>

index.js:

const app = new Vue({
  el: "#app",
  data: {
    persons: {
      John: 20,
      Mary: 19,
      Jane: 20
    }
  }
});

We can get the value and key of an object’s entry respectively with:

v-for="(age, name) in persons"

With React, we use Object.entries to do the same thing:

import React, { useState } from "react";

export default function App() {
  const [persons] = useState({
    John: 20,
    Mary: 19,
    Jane: 20
  });

  return (
    <div className="App">
      {Object.entries(persons).map(([name, age]) => (
        <div>
          {name}: {age}
        </div>
      ))}
    </div>
  );
}

The expression is getting more complex since we have to call Object.entries and then map them to the component that we want to render.

Verdict

For simple components, there isn’t too much difference between React and Vue when it comes to setting attributes.

However, we do have to remember that they’re all camel case and the names might be different from HTML.

Vue has a slight edge here since we don’t have to worry about that. Dynamic attributes can be set with : and the rest is the same.

With Vue, we have to learn the v-for directive to render collections, while we just use plain JavaScript to do that with React.

However, with React, we have to write one big expression to do that, while in Vue, we can add directives to a template to do that.

This makes rendering collections cleaner with Vue, so Vue has the slight edge here as well.

Categories
Vue

Vuelidate — Forms, Related Fields, and Nested Fields Validation

Vue.js doesn’t come with any form validation capabilities by default.

Therefore, we need to add our own form validation library or with our own code.

In this article, we’ll look at how to validate forms with Vuelidate.

Form Submission

We can check a form’s validity before submission with Vuelidate.

To do this, we can check the $invalid state before sending any requests.

For example, we can write:

<template>
  <div id="app">
    <form @submit.prevent="submit">
      <div :class="{ 'form-group--error': $v.name.$error }">
        <label>Name</label>
        <input v-model.trim="$v.name.$model">
        <div v-if="!$v.name.required">Field is required</div>
        <div
          v-if="!$v.name.minLength"
        >Name must have at least {{$v.name.$params.minLength.min}} letters.</div>
      </div>
      <div :class="{ 'error': $v.age.$error }">
        <label>Age</label>
        <input v-model.trim.lazy="$v.age.$model">
        <div
          class="error"
          v-if="!$v.age.between"
        >Must be between {{$v.age.$params.between.min}} and {{$v.age.$params.between.max}}</div>
      </div>
      <input type="submit" value="submit">
    </form>
  </div>
</template>
<script>
import { required, minLength, between } from "vuelidate/lib/validators";
export default {
  name: "App",
  data() {
    return {
      name: "",
      age: 0
    };
  },
  validations: {
    name: {
      required,
      minLength: minLength(4)
    },
    age: {
      between: between(20, 30)
    }
  },
  methods: {
    submit() {
      this.$v.$touch();
      if (this.$v.$invalid) {
        alert("error");
      } else {
        alert("submitted");
      }
    }
  }
};
</script>

We have the @submit.prevent directive to run the submit method when we click on the submit button.

In the submit method, we run this.$v.touch() to trigger form validation.

Then we check the this.$v.$invalid property to see if the form is invalid or not.

Contextified Validators

We can check related fields with contextified validators.

For example, we can write:

<template>
  <div id="app">
    <div>
      <div :class="{ 'form-group--error': $v.password.$error }">
        <label>Password</label>
        <input v-model.trim="$v.password.$model">
        <div class="error" v-if="!$v.password.required">Password is required.</div>
        <div
          class="error"
          v-if="!$v.password.minLength"
        >Password must have at least {{ $v.password.$params.minLength.min }} letters.</div>
      </div>

      <div :class="{ 'form-group--error': $v.repeatPassword.$error }">
        <label>Repeat password</label>
        <input v-model.trim="$v.repeatPassword.$model">
      </div>
      <div class="error" v-if="!$v.repeatPassword.sameAsPassword">Passwords must be identical.</div>
    </div>
  </div>
</template>
<script>
import { required, sameAs, minLength } from "vuelidate/lib/validators";
export default {
  name: "App",
  data() {
    return {
      password: "",
      repeatPassword: ""
    };
  },
  validations: {
    password: {
      required,
      minLength: minLength(6)
    },
    repeatPassword: {
      sameAsPassword: sameAs("password")
    }
  }
};
</script>

We added the sameAs validator to the repeatPassword field with the string of the field we want to compare with as the argument.

This way, we can make sure that both the password and repeatPassword fields are the same.

Data Nesting

We can validate nested data.

If a children validator has $invalid set to true , then the parent validator will also have $invalid true .

For example, we can write:

<template>
  <div id="app">
    <div>
      <div :class="{ 'form-group--error': $v.form.name.$error }">
        <label>name</label>
        <input v-model.trim="$v.form.name.$model">
        <div class="error" v-if="!$v.form.name.required">name is required.</div>
      </div>

      <div :class="{ 'form-group--error': $v.form.age.$error }">
        <label>age</label>
        <input v-model.trim="$v.form.age.$model">
      </div>
      <div class="error" v-if="!$v.form.age.required">age is required.</div>
    </div>
  </div>
</template>
<script>
import { required } from "vuelidate/lib/validators";
export default {
  name: "App",
  data() {
    return {
      form: {
        name: "",
        age: ""
      }
    };
  },
  validations: {
    form: {
      name: {
        required
      },
      age: {
        required
      }
    }
  }
};
</script>

We defined the nested fields in the object we return in data and in the validations object.

Then in the template, we just access the properties as we have them in the component code.

Conclusion

We can validate forms, related fields and nested fields with Vuelidate.

Categories
Vue

Vuelidate — Errors and Lists Validation

Vue.js doesn’t come with any form validation capabilities by default.

Therefore, we need to add our own form validation library or with our own code.

In this article, we’ll look at how to validate forms with Vuelidate.

$error vs $anyError

We can get form validation errors with the $error and $anyError validation property.

$dirty and $anyDirty checks if the forms have been modified.

For example, we can write:

<template>
  <div id="app">
    <div>
      <div :class="{ 'form-group--error': $v.name.$error }">
        <label>name</label>
        <input v-model.trim="$v.name.$model">
        <div class="error" v-if="!$v.name.required">name is required.</div>
      </div>

<div :class="{ 'form-group--error': $v.age.$error }">
        <label>age</label>
        <input v-model.trim="$v.age.$model">
      </div>
      <div class="error" v-if="!$v.age.required">age is required.</div>
    </div>
  </div>
</template>
<script>
import { required } from "vuelidate/lib/validators";
export default {
  name: "App",
  data() {
    return {
      name: "",
      age: ""
    };
  },
  validations: {
    name: {
      required
    },
    age: {
      required
    }
  }
};
</script>

Then we gave the $v.age.$error and $v.name.$error properties to get the errors.

If they’re true , then the form-group--error class will be applied.

Validation Groups

We can create validation groups to validate all the form fields together.

For example, we can write:

<template>
  <div id="app">
    <div>
      <div :class="{ 'form-group--error': $v.name.$error }">
        <label>name</label>
        <input v-model.trim="$v.name.$model">
        <div class="error" v-if="!$v.name.required">name is required.</div>
      </div>

      <div :class="{ 'form-group--error': $v.age.$error }">
        <label>age</label>
        <input v-model.trim="$v.age.$model">
        <div class="error" v-if="!$v.age.required">age is required.</div>
      </div>

      <div :class="{ 'form-group--error': $v.phone.mobile.$error }">
        <label>mobile phone</label>
        <input v-model.trim="$v.phone.mobile.$model">
        <div class="error" v-if="!$v.phone.mobile.required">mobile phone is required.</div>
      </div>

<div v-if="$v.validationGroup.$error">group is invalid.</div>
    </div>
  </div>
</template>
<script>
import { required } from "vuelidate/lib/validators";
export default {
  name: "App",
  data() {
    return {
      name: "",
      age: "",
      phone: {
        mobile: ""
      }
    };
  },
  validations: {
    name: {
      required
    },
    age: {
      required
    },
    phone: {
      mobile: {
        required
      }
    },
    validationGroup: ["name", "age", "phone.mobile"]
  }
};
</script>

We added the validationGroup property in the validations property to add a validation group.

It has an array of strings with the property names.

If the property is nested, then the property is separated by a dot.

Then in the template, we get the $v.validationGroup.$error property to see if there’re any errors in the fields in the group.

Collections Validation

We can validate collections with the $each keyword.

For instance, we can write:

<template>
  <div id="app">
    <div v-for="(v, index) in $v.people.$each.$iter">
      <div class="form-group" :class="{ 'form-group--error': v.$error }">
        <label>Name</label>
        <input v-model.trim="v.name.$model">
      </div>
      <div v-if="!v.name.required">Name is required.</div>
      <div
        v-if="!v.name.minLength"
      >Name must have at least {{ v.name.$params.minLength.min }} letters.</div>
    </div>
    <div>
      <button class="button" [@click](http://twitter.com/click "Twitter profile for @click")="people.push({name: ''})">Add</button>
      <button class="button" [@click](http://twitter.com/click "Twitter profile for @click")="people.pop()">Remove</button>
    </div>
    <div class="form-group" :class="{ 'form-group--error': $v.people.$error }"></div>
    <div
      v-if="!$v.people.minLength"
    >List must have at least {{ $v.people.$params.minLength.min }} elements.</div>
    <div v-else-if="!$v.people.required">List must not be empty.</div>
    <div v-else-if="$v.people.$error">List is invalid.</div>
    <button class="button" [@click](http://twitter.com/click "Twitter profile for @click")="$v.people.$touch">$touch</button>
    <button class="button" [@click](http://twitter.com/click "Twitter profile for @click")="$v.people.$reset">$reset</button>
  </div>
</template>
<script>
import { required, minLength } from "vuelidate/lib/validators";
export default {
  name: "App",
  data() {
    return {
      people: [
        {
          name: "mary"
        },
        {
          name: ""
        }
      ]
    };
  },
  validations: {
    people: {
      required,
      minLength: minLength(3),
      $each: {
        name: {
          required,
          minLength: minLength(2)
        }
      }
    }
  }
};
</script>

In the validations property, we have the $each property with the minLength property to set the min length of the people array.

Also, we have the minLength property in the name field to check if the name entered has the required length.

In the template, we have the $touch and $reset methods that we can use to trigger validation and reset the validation state respectively.

Conclusion

We can validate lists and check for errors with Vuelidate.