Main menu

Post navigation

Taking user input using a form is a standard feature in a single page application. In this article, I’m comparing how client-side form validation can be implemented in Angular (version 6.0.3), React (version 16.4.1), and Vue (version 2.5.16).

I’ve created a simple form with the following fields and the associated validations.

Field Name

Validations

Name

Required

Phone

Must be in a specific format: XXX-XXX-XXXX

Username

Must not be registered before (the actual validation is done on a remote server)

Password

No validations

Confirm Password

Must match Password field

Form with client-side validation

Sample Code

Angular

Angular comes with FormsModule which provides the framework to validate your form. When you add the directive NgForm to your form, the state of the controls within the form is tracked which allows invoking the validation process at the right moment. When a control enforce multiple validation rules, the specific violated rules are also tracked.

Angular not only provides several built-in validators, but it also provides the framework to create a custom validator. This custom validator is implemented as a directive and the new validation rule can be added to a control by adding its selector to that control. When validation involves two controls (such as comparing the values in two controls), the custom validator directive (in this case, PasswordConfirmedValidatorDirective) must be applied on the form element. I’ve got more intuitive way in mind (as implemented in React and Vue app) to do it, but that’s what the documentation suggests.

React

When I was looking for a React validation library, I found several libraries with different paradigms. Based on your programming experience, one paradigm will feel more intuitive than the other. I decided to use React Advanced Form to enable form validation on this app. I also installed the companion library react-advanced-form-addons which provides form controls with support to display validation errors.

Vue

Vue doesn’t provide a built-in form validation library, but its documentation provides an example how to do it by hand. It also lists a couple third-party validation libraries. I use Veevalidate for this Vue app. VeeValidate ships with a lot of built-in validation rules, including one that you can use to make sure a user enters new password correctly.

The form validation functionality provided by Angular is a good start toward a complete validation framework customized to your app. I also like the reusability of an Angular directive, but the boilerplate code adds so much noise.

Phone number validator. (Left to right: Angular, React, Vue)

To start from a scratch, React and Vue needs implementation of events (such as touched, changed, and valid) and only then we can implement the actual validation process. Finding a thirdy-party validation library may not be easy even when there are plenty of options. One solution seems more intuitive than then others and it feels like it’s better to pick the most basic one which can be used as a foundation.

React

react-router takes a different approach (called “dynamic routing”) as to when/where to apply the routing configuration. Its Router library provides routing-related components and you add them within the template (JSX code). The configuration (mapping of paths to components) is specified using directives within the template.

Vue

For a Vue app, the routing configuration is specified within main.js where the app is initialized.

./src/main.js

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

import Vue from'vue'

import VueRouter from'vue-router'

import App from'./App.vue'

import Dashboard from'./components/Dashboard.vue'

import Tasks from'./components/Tasks.vue'

import TaskDetail from'./components/TaskDetail.vue'

import PageNotFound from'./components/PageNotFound.vue'

Vue.config.productionTip=false;

Vue.use(VueRouter);

constroutes=[

{path:'/',redirect:'/dashboard'},

{path:'/dashboard',component:Dashboard},

{path:'/tasks',component:Tasks},

{path:'/detail/:id',component:TaskDetail},

{path:'*',component:PageNotFound}

];

constrouter=newVueRouter({

mode:'history',

routes

});

newVue({

render:h=>h(App),

router

}).$mount('#app')

./src/App.vue

1

2

3

4

5

6

7

8

9

10

11

12

13

14

<template>

<div id="app">

<h1>Routing App</h1>

<nav>

<router-link to="/dashboard">Dashboard</router-link>|

<router-link to="/tasks">Tasks</router-link>

</nav>

<router-view></router-view>

</div>

</template>

<script>

exportdefault{}

</script>

./src/components/Dashboard.vue

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

<template>

<div class="due-today">

<h3>Due Soon</h3>

<ulv-if="tasks && tasks.length > 0">

<liv-for="(task) in tasks"

v-bind:key="task.id">

<router-linkv-bind:to="'/detail/' + task.id">

{{task.title}}

</router-link>{{task.dueDate}}

</li>

</ul>

<templatev-else>

<p>Alldone!</p>

</template>

</div>

</template>

<script>

import taskService from'./../taskService';

exportdefault{

data(){

return{

tasks:[]

}

},

mounted(){

constmaxNumberOfTasks=3;

taskService.getTasks(maxNumberOfTasks)

.then(result=>{

this.tasks=result;

});

}

}

</script>

./src/components/TaskDetail.vue

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

<template>

<divv-if="task"class="task-detail">

<h2>{{task.title}}</h2>

<p>Due date:{{task.dueDate}}</p>

<p>Note:{{task.note}}</p>

</div>

</template>

<script>

import taskService from'./../taskService';

exportdefault{

data(){

return{

task:null

}

},

mounted(){

constid=+this.$route.params.id;

taskService.getTask(id)

.then(result=>{

this.task=result;

});

}

}

</script>

Angular’s and Vue’s routes are configured as part of initialization of the app; it happens before any of the components are rendered. React’s react-routers provides its functionalities via components–the same component concept that you use to declare a view. In a React app, you will see the declaration of router and routes within app components (whether it’s the top-level or a lower-level component). In Angular and Vue, the code pertaining to the router module and the routes don’t intermingle with that of components.

Routes definition. (Left to right: Angular, React, Vue)

To display the active view, Angular and Vue use a placeholder directive (router-outlet and router-view, respectively) while react-router uses the same route components to define route mapping and render the selected view.

Requesting data from a server via AJAX/XMLHttpRequest is ubiquitous when implementing a single page application. In this article, I’m comparing the use of AJAX in Angular (version 6.0.3), React (version 16.4.1), and Vue (version 2.5.16). I implemented the AJAX operations in a “To Do” app I created in part II.

I’ve set up a remote server which provides APIs to add a new to-do item, to remove a to-do item, and to list to-do items.

1

2

3

POST http://localhost/todo-api/todos/ (param: title)

DELETE http://localhost/todo-api/todos/ (param: Todo ID)

GET http://localhost/todo-api/todos/ (returns: Todo[] )

Angular provides a module HttpClient to allow your app to execute typical AJAX requests (POST, GET, etc). React’s documentation suggests that you can use any AJAX library with React. The documentation lists some common AJAX library such as axios, jQuery AJAX, and the browser’s built-in window.fetch. Vue hardly provides any hint regarding incorporating AJAX operations. Tucked in their website is the Cookbook section which has the article “Using Axios to Consument APIs.” I created a wrapper for axios and used it for both React and Vue

Angular’s HttpClient instance is available to be injected to any class once you import the HttpClient module from @angular/common/http library. The module provides the methods get(), post(), and other methods to do typical AJAX requests.

axios, an HTTP client library I used for React and Vue, is heavily inspired by Angular’s HttpClient, so the methods provided by axios will look familiar if you’ve used HttpClient. You can install axios using NPM.

When executing an AJAX request, typically you want to do it as early as possible but not to early as the component is loaded. A component in these three frameworks has a lifecycle and hooks are available so that an operation can be executed within the lifecycle. For an Angular, React, and Vue component, the recommendation is to execute any AJAX request the earliest inside the ngOnInit, componentDidMount, and mounted lifecycle hook, respectively.

A major difference between Angular’s HttpClient and axio‘s HTTP client is that HttpClient is based on Observable while axios library is based on Promise. For simple operations as used by this “To Do” app, there’s hardly any difference in the implementation between using an Observable or Promise-based HTTP client.