如何从具有多个组件的动态表单中 $emit 数据
How to $emit data from dynamic form with multiple components
我正在开发一款用户可以创建任务列表的应用程序。创建列表后,将从数据库中提取列表供用户使用,并select对每个任务进行适当的响应。
回应:- 是或否
选择 'No':启用原因下拉列表 select 任务未完成的原因 - 选择 'other' 选项将显示自定义原因输入框。
用户还可以为每个任务添加评论,一旦表单完成,他们就可以提交。
由于显示每个任务的组件是动态的,我不知道如何捕获表单响应。我在组件周围创建了一个 <form>
- 单击后应提交表单,但我不知道如何从组件获取数据。
App.vue
<template>
<button @click="toggleComplete">Complete All</button>
<form @submit.prevent="submitModal">
<checklist-item
v-for="taskList in myChecklist.tasks.data"
:key="taskList.id"
:taskDetails="taskList"
:marked="markAll"
>
</checklist-item>
<div class="">
<button class="" type="submit">Submit</button>
</div>
</form>
</template>
<script>
import checklistItem from "./components/checklistItem.vue";
export default {
name: "App",
components: {
checklistItem,
},
data() {
return {
markAll: false,
myChecklist: {
success: true,
name: "Checklist 1",
roomId: 1,
notes: "Notes about the checklist",
tasks: {
data: [
{
id: 1,
name: "Task 1",
frequency: "D",
status: null,
comment: null,
reason: null,
updated_at: "2021-08-09",
},
{
id: 2,
name: "Task 2",
frequency: "M",
status: null,
comment: null,
reason: null,
updated_at: "2021-08-09",
},
{
id: 3,
name: "Task 3",
frequency: "Y",
status: null,
comment: null,
reason: null,
updated_at: "2021-08-09",
},
],
},
},
};
},
methods: {
toggleComplete() {
this.markAll = !this.markAll;
},
submitModal() {
console.log("inside");
},
},
};
</script>
<style>
</style>
ChecklistItem.vue
<template>
<div class="flex justify-center items-center">
<div
class="border border-gray-200 w-11/12 bg-white rounded-lg shadow-sm hover:shadow-2xl duration-500 px-2 py-4 my-1"
>
<div class="flex flex-col m-auto w-11.5/12">
<div class="">
<div class="text-xl font-semibold">
{{ taskDetails.name }}
</div>
<div class="pb-2 sm-pb-0">
<p>Due: <strong>Today</strong></p>
</div>
<!-- Yes Button -->
<div class="yesClass flex justify-center-0 pb-2">
<input
@change="disableSelect()"
type="radio"
:checked="marked"
:name="taskDetails.id"
:id="taskDetails.id + 'yes'"
class=""
/>
<label
:for="taskDetails.id + 'yes'"
class="yesClass border text-center border-orange-400 rounded-2xl w-full py-0.5 hover:bg-green-400 hover:text-white hover:border-green-200"
>
<span>Yes</span>
</label>
</div>
<!-- No Button -->
<div class="noClass flex justify-center pb-2">
<input
@change="enableSelect()"
type="radio"
:name="taskDetails.id"
:id="taskDetails.id + 'no'"
class=""
/>
<label
:for="taskDetails.id + 'no'"
class="border text-center border-orange-400 rounded-2xl w-full py-0.5 label-checked:bg-green-200 hover:bg-red-800 hover:text-white hover:border-red-200"
>
<span>No</span>
</label>
</div>
<!-- Reason Dropdown -->
<p>Reason:</p>
<div class="disabled flex justify-center">
<br />
<select
:disabled="!notCompletedToggle"
name="reason"
id="reasons"
class="w-full mt-1 rounded-lg py-0.5 my-0.5"
:class="[notCompletedToggle ? 'bg-red-500' : '']"
ref="selectedItem"
@change="customEventToggle($event)"
>
<option value="reason_1" :selected="!notCompletedToggle">
Select Reason
</option>
<option value="reason_1">Reason 1</option>
<option value="reason_2">Reason 2</option>
<option value="reason_3">Reason 3</option>
<option value="other">Other --></option>
</select>
</div>
<div
class="flex justify-center my-0.5"
:class="{ hidden: !customReasonToggle }"
>
<input
type="text"
class="bg-gray-200 w-full rounded-md mt-1 py-0.5"
v-model="customReason"
/>
</div>
</div>
<div class="">
<div class="flex items-end justify-start text-grey">
<label>Comment:</label>
</div>
<div class="flex items-end justify-center">
<textarea
type="text"
class="bg-gray-200 rounded-lg w-full h-16"
></textarea>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
components: {},
emits: ["custom-event-toggle"],
props: ["taskDetails", "marked"],
data() {
return {
notCompletedToggle: false,
customReasonToggle: false,
customReason: "",
};
},
methods: {
customEventToggle(event) {
if (event.target.value === "other") {
this.customReasonToggle = true;
} else {
this.customReasonToggle = false;
}
},
disableSelect() {
this.notCompletedToggle = false;
this.customReasonToggle = false;
},
enableSelect() {
this.notCompletedToggle = true;
},
},
};
</script>
<style scoped>
input[type="radio"] {
display: none;
}
.yesClass input[type="radio"]:checked + label {
background-color: #78be20;
color: white;
}
.noClass input[type="radio"]:checked + label {
background-color: #da291c;
color: white;
}
</style>
您可以在每个事件上从 checklist-item
组件内部发出事件,以设置 myChecklist.tasks.data
数组中的值。
methods: {
updateData(property, value) {
this.$emit("update-form-data", {
id: this.taskDetails.id,
property,
value,
});
},
customEventToggle(event) {
this.updateData("reason", event.target.value);
if (event.target.value === "other") {
this.customReasonToggle = true;
} else {
this.customReasonToggle = false;
}
},
disableSelect() {
this.updateData("status", "YES");
this.notCompletedToggle = false;
this.customReasonToggle = false;
},
enableSelect() {
this.updateData("status", "NO");
this.notCompletedToggle = true;
},
setComment(event) {
this.updateData("comment", event.target.value);
},
}
然后在父组件中监听事件并更新你的数据数组:
<checklist-item
v-for="taskList in myChecklist.tasks.data"
:key="taskList.id"
:taskDetails="taskList"
:marked="markAll"
@update-form-data="
this.myChecklist.tasks.data.find((task) => task.id === $event.id)[
$event.property
] = $event.value
"
Here's your updated sandbox。单击提交时将数据记录到控制台。
我正在开发一款用户可以创建任务列表的应用程序。创建列表后,将从数据库中提取列表供用户使用,并select对每个任务进行适当的响应。
回应:- 是或否
选择 'No':启用原因下拉列表 select 任务未完成的原因 - 选择 'other' 选项将显示自定义原因输入框。
用户还可以为每个任务添加评论,一旦表单完成,他们就可以提交。
由于显示每个任务的组件是动态的,我不知道如何捕获表单响应。我在组件周围创建了一个 <form>
- 单击后应提交表单,但我不知道如何从组件获取数据。
App.vue
<template>
<button @click="toggleComplete">Complete All</button>
<form @submit.prevent="submitModal">
<checklist-item
v-for="taskList in myChecklist.tasks.data"
:key="taskList.id"
:taskDetails="taskList"
:marked="markAll"
>
</checklist-item>
<div class="">
<button class="" type="submit">Submit</button>
</div>
</form>
</template>
<script>
import checklistItem from "./components/checklistItem.vue";
export default {
name: "App",
components: {
checklistItem,
},
data() {
return {
markAll: false,
myChecklist: {
success: true,
name: "Checklist 1",
roomId: 1,
notes: "Notes about the checklist",
tasks: {
data: [
{
id: 1,
name: "Task 1",
frequency: "D",
status: null,
comment: null,
reason: null,
updated_at: "2021-08-09",
},
{
id: 2,
name: "Task 2",
frequency: "M",
status: null,
comment: null,
reason: null,
updated_at: "2021-08-09",
},
{
id: 3,
name: "Task 3",
frequency: "Y",
status: null,
comment: null,
reason: null,
updated_at: "2021-08-09",
},
],
},
},
};
},
methods: {
toggleComplete() {
this.markAll = !this.markAll;
},
submitModal() {
console.log("inside");
},
},
};
</script>
<style>
</style>
ChecklistItem.vue
<template>
<div class="flex justify-center items-center">
<div
class="border border-gray-200 w-11/12 bg-white rounded-lg shadow-sm hover:shadow-2xl duration-500 px-2 py-4 my-1"
>
<div class="flex flex-col m-auto w-11.5/12">
<div class="">
<div class="text-xl font-semibold">
{{ taskDetails.name }}
</div>
<div class="pb-2 sm-pb-0">
<p>Due: <strong>Today</strong></p>
</div>
<!-- Yes Button -->
<div class="yesClass flex justify-center-0 pb-2">
<input
@change="disableSelect()"
type="radio"
:checked="marked"
:name="taskDetails.id"
:id="taskDetails.id + 'yes'"
class=""
/>
<label
:for="taskDetails.id + 'yes'"
class="yesClass border text-center border-orange-400 rounded-2xl w-full py-0.5 hover:bg-green-400 hover:text-white hover:border-green-200"
>
<span>Yes</span>
</label>
</div>
<!-- No Button -->
<div class="noClass flex justify-center pb-2">
<input
@change="enableSelect()"
type="radio"
:name="taskDetails.id"
:id="taskDetails.id + 'no'"
class=""
/>
<label
:for="taskDetails.id + 'no'"
class="border text-center border-orange-400 rounded-2xl w-full py-0.5 label-checked:bg-green-200 hover:bg-red-800 hover:text-white hover:border-red-200"
>
<span>No</span>
</label>
</div>
<!-- Reason Dropdown -->
<p>Reason:</p>
<div class="disabled flex justify-center">
<br />
<select
:disabled="!notCompletedToggle"
name="reason"
id="reasons"
class="w-full mt-1 rounded-lg py-0.5 my-0.5"
:class="[notCompletedToggle ? 'bg-red-500' : '']"
ref="selectedItem"
@change="customEventToggle($event)"
>
<option value="reason_1" :selected="!notCompletedToggle">
Select Reason
</option>
<option value="reason_1">Reason 1</option>
<option value="reason_2">Reason 2</option>
<option value="reason_3">Reason 3</option>
<option value="other">Other --></option>
</select>
</div>
<div
class="flex justify-center my-0.5"
:class="{ hidden: !customReasonToggle }"
>
<input
type="text"
class="bg-gray-200 w-full rounded-md mt-1 py-0.5"
v-model="customReason"
/>
</div>
</div>
<div class="">
<div class="flex items-end justify-start text-grey">
<label>Comment:</label>
</div>
<div class="flex items-end justify-center">
<textarea
type="text"
class="bg-gray-200 rounded-lg w-full h-16"
></textarea>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
components: {},
emits: ["custom-event-toggle"],
props: ["taskDetails", "marked"],
data() {
return {
notCompletedToggle: false,
customReasonToggle: false,
customReason: "",
};
},
methods: {
customEventToggle(event) {
if (event.target.value === "other") {
this.customReasonToggle = true;
} else {
this.customReasonToggle = false;
}
},
disableSelect() {
this.notCompletedToggle = false;
this.customReasonToggle = false;
},
enableSelect() {
this.notCompletedToggle = true;
},
},
};
</script>
<style scoped>
input[type="radio"] {
display: none;
}
.yesClass input[type="radio"]:checked + label {
background-color: #78be20;
color: white;
}
.noClass input[type="radio"]:checked + label {
background-color: #da291c;
color: white;
}
</style>
您可以在每个事件上从 checklist-item
组件内部发出事件,以设置 myChecklist.tasks.data
数组中的值。
methods: {
updateData(property, value) {
this.$emit("update-form-data", {
id: this.taskDetails.id,
property,
value,
});
},
customEventToggle(event) {
this.updateData("reason", event.target.value);
if (event.target.value === "other") {
this.customReasonToggle = true;
} else {
this.customReasonToggle = false;
}
},
disableSelect() {
this.updateData("status", "YES");
this.notCompletedToggle = false;
this.customReasonToggle = false;
},
enableSelect() {
this.updateData("status", "NO");
this.notCompletedToggle = true;
},
setComment(event) {
this.updateData("comment", event.target.value);
},
}
然后在父组件中监听事件并更新你的数据数组:
<checklist-item
v-for="taskList in myChecklist.tasks.data"
:key="taskList.id"
:taskDetails="taskList"
:marked="markAll"
@update-form-data="
this.myChecklist.tasks.data.find((task) => task.id === $event.id)[
$event.property
] = $event.value
"
Here's your updated sandbox。单击提交时将数据记录到控制台。