Setting up inquiry forms with Kuroco and Nuxt.js
This tutorial explains how to set up inquiry forms for a Nuxt.js project implemented with Kuroco.
This tutorial assumes that you have a ready-to-use Kuroco-implemented Nuxt.js project. See: Creating content list page with Kuroco and Nuxt.js for a full tutorial on how to build one.
About Kuroco forms
The form function in Kuroco allows the user to define data to support the creation of HTML forms, set automatic replies, and view form data submitted by users.
You can manage form settings via the [Campaign] -> [Form] module of the admin panel.
For more information, refer to the following user guide documents:
Before your form can be used, you need to configure various settings and codes on the front-end. The sections below explain the steps to enable forms in your Kuroco and Nuxt.js project.
1. Defining your form data
To create a new form, click [Add] in the upper right corner of the form list screen.
You will be redirected to a new form editor. See: Form editor - Basic settings for a detailed description of each field. For this tutorial, we will create a sample form with the following entries:
Field | Value |
---|---|
Title | Test form |
Description | Enter description here. Enter description here. Enter description here. |
Thank you message | Enter thank-you message here. Enter thank-you message here. Enter thank-you message here. |
When you are done, click [Add] at the bottom of the screen.
You will be redirected back to the form list, which now contains your newly created form.
Note: The number displayed in the "ID" column is the unique identifier of the inquiry form.
The ID value of each entry is automatically generated and varies depending on the environment. In the above example, the ID number is 25. However, for the steps below, remember to substitute this value with the ID shown on your screen.
2. Verifying the form settings
Verify the item settings
On the form list screen, click the title of your new form.
You will be redirected to the form editor screen. From there, click the [Field settings] tab.
This will take you to the form field settings screen.
Here, you can set HTML definitions of the inquiry form items.
"name", "email", and "message" have been preset, since they are required fields in Kuroco. To add a custom field, you can define it as desired in the blank fields below "message".
For this part of the tutorial, we will use only the default fields.
Verify the responses
Click the [Answers] tab to view a list of user-submitted responses to the form.
All responses submitted via the HTML form are displayed here.
(In the above screenshot, there are no records displayed, since the HTML form has not been created yet and hence no data has been submitted.)
Details such as the response contents can be verified on this screen or in the [Report] tab to the right.
3. Setting up endpoints for the form
Next, create two endpoints as follows and enable the form function on the front-end:
- For form definition retrieval:
(GET) form
- For form data submission:
(POST) form
A. (GET) form
endpoint setup
In the sidebar menu, select the target API from [API] and click [Add new endpoint] on the endpoint list screen.
Set up your endpoint as follows:
| Field(s) | Sub-field | Setting |
| :--- | :--- | :--- |
| Path | - |
form
|
|| Enabled/Disabled | Enabled |
| Model | Category | Inquiry |
|| Model | InquiryForm, v1 |
|| Operation | details |
| Authorization | - | None |
For simplicity, we will omit the authorization settings here.
Swagger UI verification
Then, verify if the Swagger UI can retrieve the form you have defined. On the endpoint list screen, click [Swagger UI].
You will be redirected to the Swagger UI screen. Select the endpoint you created earlier.
Click [Try it out]
Enter the ID of your new form (in this case,
25
) in the "inquiry_id" field and click [Execute].
The form will be converted to JSON and displayed under "Responses".
B. (POST) form
endpoint setup
You also need to create an endpoint for submitting data from HTML to the target form.
As before, select your target API in the sidebar menu and click [Add new endpoint] on the endpoint list screen.
Set up your endpoint as shown below.
Similarly, we omit the authorization settings here for simplicity.
| Field(s) | Sub-field | Setting |
| :--- | :--- | :--- |
| Path | - |
form
|
|| Enabled/Disabled | Enabled |
| Model | Category | Inquiry |
|| Model | InquiryMessage, v1 |
|| Operation | send |
| Authorization | - | None |
When you are done, click [+Add] to save these settings.
We have now set up two endpoints:
- For form definition retrieval:
(GET) form
- For form data submission:
(POST) form
Next, let's use them to create and submit your form.
4. Additional front-end modifications
In your Nuxt installation directory, make a form
directory under pages
and create a file entitled index.vue
.
pages
- form
- index.vue
Insert the following code into pages/form/index.vue
:
<template>
<div>
<h1>Form page</h1>
<form v-if="!submitted" ref="form">
<div v-if="error" class="error">
<p v-for="(err, idx) in error" :key="idx">
{{ err }}
</p>
</div>
<div class="row--status">
<h2>Form title</h2>
<div>{{ name }}</div>
</div>
<div class="row--status">
<h2>Description</h2>
<div>
<p v-for="(line, idx) in textLines2texts(info)" :key="idx">
{{ line }}
</p>
</div>
</div>
<div class="row--status">
<h2>Thank you message</h2>
<div>
<p v-for="(line, idx) in textLines2texts(thanksText)" :key="idx">
{{ line }}
</p>
</div>
</div>
<div class="row--status">
<h2>Form fields</h2>
<div class="row--internal">
<div v-for="col in cols" :key="col.key">
<p>[{{ col.title }}]</p>
<pre>{{ col }}</pre>
</div>
</div>
</div>
<div v-for="col in cols" :key="col.objKey" class="row--form">
<h2>[{{ col.title }}]</h2>
<input :name="col.objKey" type="text" />
</div>
<div class="row--bottom-next">
<button @click="handleOnSubmit">submit</button>
</div>
</form>
<form v-else>
<div class="row--status">
<h2>Inquiry ID</h2>
<div>
{{ submittedId }}
</div>
</div>
<div class="row--status">
<h2>Thank you message</h2>
<div>
<p v-for="(line, idx) in textLines2texts(thanksText)" :key="idx">
{{ line }}
</p>
</div>
</div>
<div class="row--bottom-back">
<button @click="handleOnBack">back</button>
</div>
</form>
</div>
</template>
<script>
const FORM_ID = 25 // ID of the form
export default {
async asyncData({ $axios }) {
const response = await $axios.$get(
process.env.BASE_URL + `/rcms-api/2/form/${FORM_ID}`
)
return {
name: response.details.inquiry_name,
info: response.details.inquiry_info,
thanksText: response.details.thanks_text,
cols: Object.entries(response.details.cols).map(([k, v]) => ({
objKey: k,
...v,
})),
}
},
data: () => {
return {
submitted: false,
submittedId: null,
error: null,
}
},
methods: {
textLines2texts(textLines = '') {
return textLines.split('\r\n')
},
async handleOnSubmit(e) {
e.preventDefault()
// collect input elements
const formInputElements = Array.from(this.$refs.form.elements).filter(
(elm) => elm.tagName.toLowerCase() === 'input'
)
// transform key:value inputs to an object
const body = formInputElements
.map((elm) => ({ [elm.name]: elm.value }))
.reduce((prev, cur) => ({ ...prev, ...cur }), {})
try {
// post data
const { id } = await this.$axios.$post(
process.env.BASE_URL + `/rcms-api/2/form?id=${FORM_ID}`,
body
)
this.error = null
this.submittedId = id
this.submitted = true
} catch (e) {
this.error = [`${e}`, ...e.response.data.errors]
}
},
handleOnBack(e) {
e.preventDefault()
this.submitted = false
},
},
}
</script>
<style scoped>
input {
width: 100%;
border: none;
}
.error {
color: red;
}
.error > *:first-child {
font-weight: bold;
}
.row--status {
display: flex;
border-top: 1px solid black;
}
.row--status > *:first-child {
background-color: yellow;
min-width: 15rem;
max-width: 15rem;
border-right: 1px solid black;
}
.row--form {
display: flex;
border-top: 1px solid black;
}
.row--form > *:first-child {
background-color: aquamarine;
min-width: 15rem;
max-width: 15rem;
border-right: 1px solid black;
}
.row--bottom-next {
padding: 8px 16px;
display: flex;
justify-content: flex-end;
}
.row--bottom-back {
padding: 8px 16px;
display: flex;
justify-content: flex-start;
}
.row--internal {
display: flex;
}
form > *:nth-last-child(2) {
border-bottom: 1px solid black;
}
</style>
For const FORM_ID = 25
above, substitute the ID value with your own.
For /rcms-api/2/form/${FORM_ID}
and /rcms-api/2/form?id=${FORM_ID}
, enter the path shown on your endpoint list screen.
Browser verification
Next, verify the above file in youe browser.
If your local server is down, run npm run dev
to access http://localhost:3000/form
. You should see the screen below:
In the table below, the yellow rows display data extracted from the retrieved form definition.
Data content | Method of access |
---|---|
Form title | (response).details.inquiry_name |
Description | (response).details.inquiry_info |
Thank you message | (response).details.thanks_text |
Form fields | (response).details.cols |
As shown in the asyncData()
source code, you can verify the form definition retrieval using the correspondence table above. Default form items other than [Category] are returned as objects.
You can use the [Network] tab in the Chrome developer console to verify more detailed network information sent to and from Kuroco.
Send the HTML form data
Now we can send data from the HTML form based on the retrieved data definition. The green rows represent the input fields of the HTML form. Enter the values shown below:
| Field | Input value |
| :--- | :--- |
| [name] |
Jane Doe
|
| [email] | test@example.com
|
| [message] | Test message.
|
Clicking [submit] sends the input data and redirects you to the next screen.
As shown by the
handleOnSubmit()
source code, this operation sends [Form field] data to Kuroco.
Data verification in Kuroco
On the form list screen, click [Test form].
Click the [Answers] tab to view the list of form responses received. You should see the entry you submitted earlier.
You can click the "No." link ([159] in this example) to view the response details, which contain data submitted via the HTML form.
5. Form validation
Lastly, let's test the form validation function.
Revisit the form page and enter an invalid value in the [email] field. Sample input:
| Field | Input value |
| :--- | :--- |
| [name] |
Error Test
|
| [email] | mail
|
| [message] | Form validation error message.
|
After you click [submit], an error message will be displayed at the top of the screen.
The above procedure verifies Kuroco's server-side validation. When an error occurs, the error content and HTTP status code are returned in the response body. As seen in the source code, you need to implement error handling on the front-end as well.
To validate dynamic forms, you will need custom implementations based on the values obtained from Kuroco.
6. Custom fields
In addition to the default form fields, you can freely define custom fields following the steps below.
Add a custom field
On the form list screen, click [Test form].
Click the [Item settings] tab to display the inquiry field settings screen.
A. Single-line text box
To set up a single-line text field, enter the values shown below in a blank custom entry:
| Field | Input value |
| :--- | :--- |
| Title |
item
|
| Required attribute | Optional |
| Answer format / Input restriction | Short text (InputBox) |
| Options settings | (Leave blank) |
As shown in the table above, you can also define validation attributes in "Required attribute" and "Options settings" to return input restriction content based on the form field attributes.
When you are done, click [Update] near the bottom of the screen.
Go back to the form page and verify that the form definition obtained from Kuroco has been updated. You should see that
item
has been added to [Form fields].
Now we can input some data to verify that the new [item] field is actually sending information to Kuroco. Fill in the green boxes as follows:
| Field | Input value |
| :--- | :--- |
| [item] |
Custom field
|
| [name] | Jane Doe
|
| [email] | test@example.com
|
| [message] | Custom field message.
|
Click [submit] to send the data. Then, click the [Answers] tab on the Kuroco form editor screen to display the list of responses. Verify that the new entry has been added.
As before, click the "No." link ([166] in this example) to view the response details. The newly added field "item" should now be included.
B. Date entry
This field type allows users to enter the date in YYYY/MM/DD
format.
Setup
To set up a date input field, enter the values shown below in a blank custom entry:
| Field | Input value |
| :--- | :--- |
| Title |
date
|
| Required attribute | Optional |
| Answer format / Input restriction | Date format |
| Options settings | (Leave blank) |
For the verification step, please clear any other custom fields you have set up prior.
As shown in the table above, you can also define validation attributes in "Required attribute" and "Options settings" to return input restriction content based on the form field attributes.
When you are done, click [Update] near the bottom of the screen.
Go back to the form page and verify that the form definition obtained from Kuroco has been updated.
Now we can input some data to verify that the new [date] field is actually sending information to Kuroco. Fill in the green boxes as follows:
| Field | Input value |
| :--- | :--- |
| [name] |
Jane Doe
|
| [date] | 1900/01/01
|
| [email] | test@example.com
|
| [message] | Date field message.
|
Click [submit] to send the data. Then, click the [Answers] tab on the Kuroco form editor screen to view the new response and verify the submitted data.
Validation check
Dates can be validated in Kuroco. For example, let's set up a validation check for dates between 10 years ago and the present.
In the [Field settings] tab of the form editor, click [Settings] next to the custom "date" field.
In the settings dialog, enter
-10years
for the "Relative start offset" field under [Input type].
Refer to the reference guide List of available fields for the inquiry form: Date format for more information.
After you implement this validation check, entering a date over 10 years before the current date will result in an error. To test this, enter 1900/01/01
in the "date" field of the form page as before and click [submit].
Field | Input value |
---|---|
[name] | Jane Doe |
[date] | 1900/01/01 |
[email] | test@example.com |
[message] | Date field message. |
Verify the error response through the message displayed at the top of the screen (scroll to the top if it is beyond the display range).
Then, input a date within 10 years from the current date and click [submit]. For this tutorial, we will use
2022/04/01
as an example.
Verify that the data is sent successfully.
C. File upload
This field type allows you to upload and submit files in the inquiry form.
Setup
To set up a file upload field, enter the values shown below in a blank custom entry:
| Field | Input value |
| :--- | :--- |
| Title |
file
|
| Required attribute | Optional |
| Answer format / Input restriction | File |
| Options settings | (Leave blank) |
You can also define validation attributes in "Required attribute" and "Options settings" to return input restriction content based on the form field attributes.
When you are done, click [Update] near the bottom of the screen to save these settings.
Go back to the form page and verify that the form definition obtained from Kuroco has been updated.
Create file upload endpoint
The implementation process is as follows:
- Upload your file to Kuroco.
- Submit the ID of the uploaded file.
In order to do that, you need to first create an endpoint to receive uploads. Select your target API in the sidebar menu and click [Add new endpoint] on the endpoint list screen.
Enter the following settings in the endpoint configuration dialog:
| Field(s) | Sub-field | Setting |
| :--- | :--- | :--- |
| Path | - |
file
|
| | Enabled/Disabled | Enabled |
| Model | Category | Files |
| | Model | Files, v1 |
| | Operation | upload
|
| Authorization | - | None |
For simplicity, we will omit the authorization settings here.
Swagger UI verification
The next step is to verify if Swagger UI can retrieve the new form definition. On the endpoint list screen, click [Swagger UI].
On the Swagger UI screen, select the file upload endpoint you created earlier.
Click [Try it out].
In the input field labeled "file", select a sample file from your local drive and click [Execute]. For this tutorial, we will use the logo image
kuroco.png
.
The file is uploaded and stored in a temporary location indicated by the
file_id
path.
You can view and verify the uploaded file by accessing the URL admin panel host name + file_id
in your browser.
Form modification and file submission
Next, update pages/form/index.vue
.
Modify the input field corresponding to the file upload field to enable file inputs:
<div v-for="col in cols" :key="col.objKey" class="row--form">
<h2>[{{ col.title }}]</h2>
- <input :name="col.objKey" type="text" />
+ <input v-if="col.title === 'file'" :name="col.objKey" type="file" @change="uploadFile" />
+ <input v-else :name="col.objKey" type="text" />
</div>
<div class="row--bottom-next">
Also, set up the form to send the file to the endpoint as soon as it is uploaded and save the file_id
in the response:
data: () => {
return {
submitted: false,
submittedId: null,
error: null,
+ file_id: null,
}
},
methods: {
+ async uploadFile(e) {
+ const fm = new FormData();
+ fm.append('file', e.target.files[0]);
+
+ const { file_id } = await this.$axios.$post(
+ process.env.BASE_URL + `/rcms-api/2/file`,
+ fm,
+ {
+ headers: {
+ 'Content-Type': 'multipart/form-data', // required to post file as a binary
+ },
+ }
+ );
+ this.file_id = file_id;
+ },
textLines2texts(textLines = '') {
For the sent data, manually set the file_id
to the corresponding data input of the file submission field:
.map((elm) => ({ [elm.name]: elm.value }))
.reduce((prev, cur) => ({ ...prev, ...cur }), {})
+ // apply file_id instead of the actual file input value
+ body.ext_01 = {
+ file_id: this.file_id,
+ };
+
try {
// post data
Now, upload the image on the front-end and verify that the new file is sent to Kuroco. On the form page, fill in the green boxes as follows:
| Field | Input value |
| :--- | :--- |
| [name] |
Jane Doe
|
| [file] | kuroco.png |
| [email] | test@example.com
|
| [message] | File upload message.
|
Click [submit] to send the data. Then, click the [Answers] tab on the Kuroco form editor screen to display the list of responses. Verify that the new entry has been added.
As before, click the "No." link ([176] in this example) to view the response details. The newly added field "file" should now be included.
7. Front-end validation of custom fields
So far, we have covered validation procedures in Kuroco, which is only the back-end side of things. To perform further validation on the front-end, you will need to set it up on your own. Below is an example of a simple front-end validation check when adding a custom date field.
Kuroco returns the validation content you defined when retrieving the form content in a GET request. As shown on the form page, the options
attribute is retrieved in the GET response.
Set this value as
min
in the HTML input.
First, since the validator value is compatible with the PHP function strtotime()
, we need to install a library for JavaScript operations. Run the following code in your terminal:
npm install locutus
Next, modify pages/form/index.vue
to import the library into the component (i.e., make it available):
</template>
<script>
+import strtotime from 'locutus/php/datetime/strtotime';
+
const FORM_ID = 21 // Substitute with your own form ID.
export default {
Implement methods for strtotime()
and the dependent parser:
},
methods: {
+ strtotime,
+ getMin(startPeriodStr) {
+ const minDateNum = strtotime(startPeriodStr) * 1000; // to millisec
+ return new Date(minDateNum).toJSON().split('T')[0] // to YYYY-MM-DD
+ },
textLines2texts(textLines = '') {
return textLines.split('\r\n')
},
Finally, update the contents of the HTML template:
<div v-for="col in cols" :key="col.objKey" class="row--form">
<h2>[{{ col.title }}]</h2>
- <input :name="col.objKey" type="text" />
+ <input v-if="col.title === 'date'" type="date" :min="getMin(col.options.minPeriod)" />
+ <input v-else :name="col.objKey" type="text" />
</div>
<div class="row--bottom-next">
After the implementation is complete, revisit the form page and verify that values prior to the specified date can no longer be selected.
Support
If you have any other questions, please contact us or check out Our Slack Community.