# Creating and Updating Contacts From the Frontend | Full-Stack Google Contacts Clone with AdonisJS Framework (Node.js) and Quasar Framework (Vue.js)

**Author:** Ndianabasi Udonkang  
**Published:** 2021-11-09

In this lesson, we improved the frontend component and store files to allow the creation and edit of contacts from the frontend.

---

## Tags

- [JavaScript](/llms/technical-blog/tag/javascript.md)
- [Nodejs](/llms/technical-blog/tag/nodejs.md)
- [Vuejs](/llms/technical-blog/tag/vuejs.md)
- [Adonisjs](/llms/technical-blog/tag/adonisjs.md)
- [Quasar Framework](/llms/technical-blog/tag/quasar-framework.md)

## Part of Series: [Full-Stack Google Contacts Clone with Node.js (Adonisjs Framework) and Vue.js (Quasar Framework)](/llms/technical-blog/series/clnwu9bc991hiu3wo2vwmw45/full-stack-google-contacts-clone-with-node-js-adonisjs-framework-and-vue-js-quasar-framework.md)

This article is part of the **[Full-Stack Google Contacts Clone with Node.js (Adonisjs Framework) and Vue.js (Quasar Framework)](/llms/technical-blog/series/clnwu9bc991hiu3wo2vwmw45/full-stack-google-contacts-clone-with-node-js-adonisjs-framework-and-vue-js-quasar-framework.md)** series.

### Articles in this Series:

- [Introduction to Full-Stack Google Contacts Clone with Node.js (Adonisjs Framework) and Vuejs (Quasar Framework)](/llms/technical-blog/article/xe5mlxg43s9rpx1pxsvfdp3r/introduction-to-full-stack-google-contacts-clone-with-node-js-adonisjs-framework-and-vuejs-quasar-framework.md)
- [Workspace Setup | Full-Stack Google Contacts Clone with Adonis.js/Node.js and Quasar (Vue.js)](/llms/technical-blog/article/fo8str8yjpkz5dygxg875bpw/workspace-setup-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-vue-js.md)
- [Frontend Overview | Full-Stack Google Contacts Clone with Adonis.js/Node.js and Quasar (Vue.js)](/llms/technical-blog/article/nxgmng6fhf1cwjk30coflro2/frontend-overview-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-vue-js.md)
- [The Left Drawer | Full-Stack Google Contacts Clone with Adonis.js/Node.js and Quasar (Vue.js)](/llms/technical-blog/article/m6fagvy2il5h65llxxbbl9os/the-left-drawer-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-vue-js.md)
- [Improve The Header | Full-Stack Google Contacts Clone with Adonis.js/Node.js and Quasar (Vue.js)](/llms/technical-blog/article/jjwbxcg450jmkkcrrmkmwvwj/improve-the-header-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-vue-js.md)
- [New Contact Form Design | Full-Stack Google Contacts Clone with Adonis.js/Node.js and Quasar (Vue.js)](/llms/technical-blog/article/ebguwpkntk3empakunrki4dq/new-contact-form-design-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-vue-js.md)
- [Validating the Contact Form with Vuelidate | Full-Stack Google Contacts Clone with Adonis.js/Node.js and Quasar (Vue.js)](/llms/technical-blog/article/z0xr9m2ljler2cwnpsw2ycwa/validating-the-contact-form-with-vuelidate-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-vue-js.md)
- [Designing the Contacts Table | Full-Stack Google Contacts Clone with Adonis.js/Node.js and Quasar (Vue.js)](/llms/technical-blog/article/h2p1x1z406ib38zu2dci3jur/designing-the-contacts-table-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-vue-js.md)
- [Designing the Contacts Table (Part 2) | Full-Stack Google Contacts Clone with Adonis.js/Node.js and Quasar (Vue.js)](/llms/technical-blog/article/j0iscua9gg8ekuz8ifh6chpn/designing-the-contacts-table-part-2-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-vue-js.md)
- [Refactoring the Main Layout | Full-Stack Google Contacts Clone with Adonis.js/Node.js and Quasar (Vue.js)](/llms/technical-blog/article/uktmlqsivwtr3cvnpld59k9q/refactoring-the-main-layout-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-vue-js.md)
- [Improving User Experience with the Contacts Table | Full-Stack Google Contacts Clone with Adonis.js/Node.js and Quasar (Vue.js)](/llms/technical-blog/article/dzs812auf61ej7qu2cg726dh/improving-user-experience-with-the-contacts-table-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-vue-js.md)
- [Designing the Contact Details Page | Full-Stack Google Contacts Clone with Adonis.js/Node.js and Quasar (Vue.js)](/llms/technical-blog/article/kf9pz97n63fvgfrcy5viwzrg/designing-the-contact-details-page-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-vue-js.md)
- [Creating the Contact Edit Page | Full-Stack Google Contacts Clone with Adonis.js/Node.js and Quasar (Vue.js)](/llms/technical-blog/article/fmr90prj84c9zn0633jc368g/creating-the-contact-edit-page-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-vue-js.md)
- [How Software Backends Work | Full-Stack Google Contacts Clone with AdonisJs (Node.js) and Quasar Framework (Vue.js)](/llms/technical-blog/article/aca8fcrghz70nn1wqg3uzbum/how-software-backends-work-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-framework-vue-js.md)
- [Setting Up The Backend | Full-Stack Google Contacts Clone with AdonisJs (Node.js) and Quasar Framework (Vue.js)](/llms/technical-blog/article/fxb49fmz9ljbwrimbnnzudfv/setting-up-the-backend-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-framework-vue-js.md)
- [Why Choose the AdonisJs Framework? | Full-Stack Google Contacts Clone with AdonisJs (Node.js) and Quasar Framework (Vue.js)](/llms/technical-blog/article/lnhm5oudx34yo2869gmcms37/why-choose-the-adonis-js-framework-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-framework-vue-js.md)
- [Setting Up Our API Server with AdonisJs Framework | Full-Stack Google Contacts Clone with AdonisJs (Node.js) and Quasar Framework (Vue.js)](/llms/technical-blog/article/x1jgmet84aqj9qggu5mulkh0/setting-up-our-api-server-with-adonis-js-framework-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-framework-vue-js.md)
- [Setting Up Postman with the API Server | Full-Stack Google Contacts Clone with AdonisJS (Node.js) and Quasar Framework (Vue.js)](/llms/technical-blog/article/v4qehksislosmuy92qgjr4ct/setting-up-postman-with-the-api-server-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-framework-vue-js.md)
- [The Model-View-Controller Design Pattern in AdonisJS | Full-Stack Google Contacts Clone with AdonisJS (Node.js) and Quasar Framework (Vue.js)](/llms/technical-blog/article/h5wqql65iejop5xrplujw458/the-model-view-controller-design-pattern-in-adonis-js-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-framework-vue-js.md)
- [Create Column Definitions & Insert New Contacts | Full-Stack Google Contacts Clone with AdonisJS (Node.js) and Quasar Framework (Vue.js)](/llms/technical-blog/article/asc2emsho4u73r6jb2gxjddw/create-column-definitions-and-insert-new-contacts-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-framework-vue-js.md)
- [Data Validation & Sanitisation with AdonisJS | Full-Stack Google Contacts Clone with AdonisJS (Node.js) and Quasar Framework (Vue.js)](/llms/technical-blog/article/bcey0ac7m5sbs9hqy1h824sl/data-validation-and-sanitisation-with-adonis-js-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-framework-vue-js.md)
- [Creating a Middleware and Updating a Contact | Full-Stack Google Contacts Clone with AdonisJS (Node.js) and Quasar Framework (Vue.js)](/llms/technical-blog/article/oqxzmtgfy1r3oewpnedc7wf6/creating-a-middleware-and-updating-a-contact-full-stack-google-contacts-clone-with-adonis-js-node-js-and-quasar-framework-vue-js.md)
- [Fetching and Deleting a Contact with AdonisJS | Full-Stack Google Contacts Clone with AdonisJS Framework (Node.js) and Quasar Framework (Vue.js)](/llms/technical-blog/article/p6bh0ponq43u3vi6o8uww84x/fetching-and-deleting-a-contact-with-adonis-js-full-stack-google-contacts-clone-with-adonis-js-framework-node-js-and-quasar-framework-vue-js.md)
- [Using Model Factories and Seeders in AdonisJS | Full-Stack Google Contacts Clone with AdonisJS Framework (Node.js) and Quasar Framework (Vue.js)](/llms/technical-blog/article/cfotveuxbgjtdp12l6pzcb2y/using-model-factories-and-seeders-in-adonis-js-full-stack-google-contacts-clone-with-adonis-js-framework-node-js-and-quasar-framework-vue-js.md)
- [Creating and Registering a Vuex Module | Full-Stack Google Contacts Clone with AdonisJS Framework (Node.js) and Quasar Framework (Vue.js)](/llms/technical-blog/article/cw96ewnzujgsz2e2garhbuzb/creating-and-registering-a-vuex-module-full-stack-google-contacts-clone-with-adonis-js-framework-node-js-and-quasar-framework-vue-js.md)
- [Connecting UI Components to the Vuex Store | Full-Stack Google Contacts Clone with AdonisJS Framework (Node.js) and Quasar Framework (Vue.js)](/llms/technical-blog/article/fdyqp17yehbnqrjvjvab4b5b/connecting-ui-components-to-the-vuex-store-full-stack-google-contacts-clone-with-adonis-js-framework-node-js-and-quasar-framework-vue-js.md)
- [Connecting the Frontend to the API Server | Full-Stack Google Contacts Clone with AdonisJS Framework (Node.js) and Quasar Framework (Vue.js)](/llms/technical-blog/article/fk4262359gg3g7f0jn95fn9b/connecting-the-frontend-to-the-api-server-full-stack-google-contacts-clone-with-adonis-js-framework-node-js-and-quasar-framework-vue-js.md)
- **Creating and Updating Contacts From the Frontend | Full-Stack Google Contacts Clone with AdonisJS Framework (Node.js) and Quasar Framework (Vue.js)** (Current Article)
- [Uploading Files and Creating Avatars for Contacts With AdonisJS and Axios](/llms/technical-blog/article/hg9ilaubqesm8angg0rhrjp9/uploading-files-and-creating-avatars-for-contacts-with-adonis-js-and-axios.md)
- [Deleting a Contact with AdonisJS and Vuejs](/llms/technical-blog/article/zdr4pxmgcax2dsfnwimhty0g/deleting-a-contact-with-adonis-js-and-vuejs.md)

---

## Article Content

In this lesson, we will make few changes to the frontend and API server so that we can create and update contacts from the frontend of the Google Contacts Clone app.

Let's create a new branch of our project:

```bash
# Make sure you are within your project
git checkout -b 19-create-and-update-contacts-from-the-frontend
```

## Pre-requisites

Let's update dependencies in our frontend (that is, the Quasar Framework).

```bash
# Change into the `ui` directory
cd ui

# check for upgradable packages
quasar upgrade
# if you get the error: `Command not found`, 
# access the `quasar` command directly
./node_modules/.bin/quasar upgrade

# do the actual upgrade
quasar upgrade --install
# if you get the error: `Command not found`, 
# access the `quasar` command directly
./node_modules/.bin/quasar upgrade --install
```

## Improving the `ContactsController`

Open the `api/app/Controllers/Http/ContactsController.ts` file. Refer to [this snapshot](https://github.com/ndianabasi/google-contacts/blob/20-create-and-update-contacts-from-the-frontend/api/app/Controllers/Http/ContactsController.ts) of the file. Copy-and-paste the content of the snapshot into the `api/app/Controllers/Http/ContactsController.ts` file.

We will make the following changes:

At Line 13, we add the `orderBy` query method so that we can sort the paginated results by `first_name` in ascending order.

```diff
      const contacts = await Contact.query()
        .select(['id', 'first_name', 'surname', 'email1', 'phone_number1', 'company', 'job_title'])
+        .orderBy('first_name', 'asc')
        .paginate(page, perPage)
```

At Line 90, within the `store` method, we return just the `id` property after the contact is created or edited. Why? The frontend is will be programmed to redirect to the `Contact View` page using the `id` of the newly-created or edited contact. We do not need to send down the entire details of the contact. Rather, we need just the `id` of the created contact. The frontend will use that `id` to navigate to the `Contact View` page and the full details of the contact will be fetched by that view. The same applies when we edit a contact at Line 161 (within the `update` method).

At Line 90:

```diff
-      return response.created({ message: 'Contact was created', data: contact })
+      return response.created({ message: 'Contact was created', data: contact.id })
```

At Line 90:

```diff
-      return response.created({ message: 'Contact was edited', data: requestedContact })
+      return response.created({ message: 'Contact was edited', data: requestedContact?.id })
```

Save the `ContactsController` file. Start the API server.

```bash
cd api && yarn serve
```

Back to the frontend. We'll begin by improving the types on the frontend.

Open the `ui/src/types/index.ts` file. Refer to [this snapshot](https://github.com/ndianabasi/google-contacts/blob/20-create-and-update-contacts-from-the-frontend/ui/src/types/index.ts) of the file. Copy-and-paste the content of the snapshot into the `ui/src/types/index.ts` file.

At Line 98, we allow the `response.data.data` property to allow `string`s value. This is important since we are now returning the `id` after creating or editing a contact.

```diff
-  data: Record<string, unknown>;
+  data: Record<string, unknown> & string;
```

From Lines 120 - 128, we define the `ValidationError` interface to properly type the validation errors we receive from the API server.

```ts
interface ValidationError {
  data?: {
    error?: {
      messages?: {
        errors?: Array<{ field: string; message: string; rule: string }>;
      };
    };
  };
}
```

At Line 131, we add the `ValidatorError` interface to the `HttpError` interface:

```diff
export interface HttpError extends AxiosError {
-   response?: HttpResponse;
+   response?: HttpResponse & ValidationError;
}
```

## Improve the `axios.ts` Boot File

Open the `ui/src/boot/axios.ts` file. Refer to [this snapshot](https://github.com/ndianabasi/google-contacts/blob/20-create-and-update-contacts-from-the-frontend/ui/src/boot/axios.ts) of the file. Copy-and-paste the content of the snapshot into the `ui/src/boot/axios.ts` file.

At Line 64, improve the path of the validation error in the error response object:

```diff
-        const validationErrors = error?.response?.data?.errors;
+        const validationErrors = error?.response?.data?.error?.messages?.errors;
```

## Improve the `contacts` Module `actions.ts` File

Open the `ui/src/store/contacts/actions.ts` file. Refer to [this snapshot](https://github.com/ndianabasi/google-contacts/blob/20-create-and-update-contacts-from-the-frontend/ui/src/store/contacts/actions.ts) of the file. Copy-and-paste the content of the snapshot into the `ui/src/store/contacts/actions.ts` file.

Within the `LOAD_CURRENT_CONTACT` action, at Line 21, improve the typing of the `response.data.data` property:

```diff
-          const currentContact = response.data.data as Contact;
+          const currentContact = response.data.data as unknown as Contact;
```

Then below the `LOAD_CONTACTS` action, add new action named: `CREATE_CONTACT` as shown below:

```ts
  CREATE_CONTACT(
    ctx,
    {
      editMode,
      payload,
      contactId,
    }: { editMode: boolean; payload: Contact; contactId?: string }
  ): Promise<Contact["id"]> {
    console.log(payload);

    return new Promise(async (resolve, reject) => {
      if (!editMode) {
        await api
          .post("/contacts", payload)
          .then((response: HttpResponse) => {
            const newContactId = response.data.data as Contact["id"];
            return resolve(newContactId);
          })
          .catch((error) => reject(error));
      } else {
        await api
          .put(`/contacts/${contactId}`, payload)
          .then((response: HttpResponse) => {
            const editContactId = response.data.data as Contact["id"];
            return resolve(editContactId);
          })
          .catch((error) => reject(error));
      }
    });
  },
```

What's going on in this new action?

We are not using any of the `getters`, `commit`, or `dispatch` properties of the `ctx`. So, no need to destructure the `ctx` object. The action receives an object containing two mandatory properties (`editMode` and `payload`) and one `optional` property (`contactId`). The `payload` property contains the form object of the contact we want to edit or create. The `editMode` property indicates if the payload is sent in `edit mode` or otherwise. If `false`, the `api.post()` method will be used to create a new contact and the `contactId` property is not necessary. The `response` will contain the `id` of the newly-created contain which we `resolve` so that it is accessible in the `initiator` function in the `CreateContact.vue` component and used to redirect to the `Contact View` page. If `editMode` is `true`, then the `api.put()` method will be used to edit the contact and the `contactId` property is required. Again, the `response` will contain the `id` of the edited contact.

## Implement Contact Creation and Editing in the `CreateContact.vue` Component

Open the `ui/src/pages/contacts/CreateContact.vue` file. Refer to [this snapshot](https://github.com/ndianabasi/google-contacts/blob/20-create-and-update-contacts-from-the-frontend/ui/src/pages/contacts/CreateContact.vue) of the file. Copy-and-paste the content of the snapshot into the `ui/src/pages/contacts/CreateContact.vue` file.

At Line 69, we import the `useRouter` hook from `vue-router`.

```diff
+ import { useRouter } from "vue-router";
```

Within the `setup` hook, we instantiate the `router` object at Line 95.

```diff
+ const router = useRouter();
```

At Line 298, we manually create the properties of the object returned from the `submitPayload` computed property. This is because the object returned from the earlier implementation does not work when sent off via an API request.

```ts
    const submitPayload = computed(() => ({
      birthday: form.birthday.value,
      city: form.city.value,
      company: form.company.value,
      country: form.country.value,
      email1: form.email1.value,
      email2: form.email2.value,
      firstName: form.firstName.value,
      jobTitle: form.jobTitle.value,
      notes: form.notes.value,
      phoneNumber1: form.phoneNumber1.value,
      phoneNumber2: form.phoneNumber2.value,
      postCode: form.postCode.value,
      state: form.state.value,
      streetAddressLine1: form.streetAddressLine1.value,
      streetAddressLine2: form.streetAddressLine2.value,
      surname: form.surname.value,
      website: form.website.value,
    }));
```

At Line 318, we make the `submitForm` asynchronous since we need to `await` the store actions.

At Line 331 to 347, we dispatch the `contacts/CREATE_CONTACT` action with the appropriate payload when the component is in `editMode` or otherwise.

When a non-error response is gotten, we fetch the edited or created `contactId` from the callback function of the `then` promise method.

At Line 338 to 341, we notify the user when the contact is created or edited.

At Line 343 to 346, we navigate to the `view_contact` route using the `contactId` as the route parameter.

Those are all the changes for this branch. Save all files, serve both the frontend and API server. Open the homepage to load the contact table. Click on a contact to view it. Edit the contact with new values. On the top toolbar, click `Create` and click `New Contact`. Fill the contact form and submit to create a new contact. Play around with the edit and creation processes.

```bash
# If the frontend is not served, serve it:
cd ui
yarn serve

# Split the terminal and serve the backend if it is not served
cd api
yarn serve
```

```bash
git add .
git commit -m "feat: complete creation and update of contacts from the frontend"
git push origin 19-create-and-update-contacts-from-the-frontend
git checkout master
git merge master 19-create-and-update-contacts-from-the-frontend
git push origin master
```


*This document was generated from the live article page on https://ndianabasi.com/technical-blog/article/t15w2s3ao9jo74l96stjo7z6/creating-and-updating-contacts-from-the-frontend-full-stack-google-contacts-clone-with-adonis-js-framework-node-js-and-quasar-framework-vue-js • 2026-06-07*
