VueJS-在 v-for 循环中呈现表单,该循环引用最初为空的对象数组
VueJS- Rendering form in a v-for loop that references an initially empty array of objects
问题陈述:
我正在尝试设计一种涉及在每次 Add button
单击时复制 Parties Being Served
表单字段的设计。单击 Add Button
时,相应的 PartyInfo
对象将添加到 PartyInfoList
数组中
在BaseButtonList.vue文件中,我使用PartyInfoList
数组来设置v-for循环
<base-card
v-for="(data, index) of partiesInfoList" :key="index"
ref="childComponent"
@add-parties="updatePartiesInfoList"
@delete-party="deleteParty(index)"
:lastElement="index === partiesInfoListLength - 1"
>
但是,重要的是要注意最初数组没有元素。但是,由于我没有其他方法可以将数据输入到数组中,因此尽管 partiesInfoList
数组的元素为零,我还是不得不加载表单。我通过使用虚拟数据设置 partiesInfoList
来实现这一点。这允许显示初始表单。当 Add Another
按钮被点击时,第一个真正的条目将被推送到 partiesInfoList
.
的第二个索引
但是,这会在从数组中删除条目时导致严重问题。当我控制台记录输出时,splice
确实正常运行。但是,Vue 最终从 DOM.
中删除了错误的元素
我使用了唯一的 index
密钥,也尝试了其他可能的密钥,但都产生了相同的有害错误。任何帮助将不胜感激。我认为这是一个非常棘手的设计模式,我可以想到更简单的替代方案,但我想让它成为一个挑战。也许我可以设置更好的数据流或其他东西。
附上代码
BaseCard.vue
<template>
//contains the template for the input form element
</template>
<script>
import { random } from '@amcharts/amcharts4/.internal/core/utils/String';
import { EventBus } from './bus.js';
export default {
emits:['add-parties','delete-party'],
props:['lastElement'],
data() {
return {
partyInfo:
{
id: '',
fullName: '',
preAuthorize: '',
serviceAddress: '',
},
validation: {
fullNameIsValid: true,
serviceAddressIsValid: true
},
hideAddButton: false,
formIsValid: true,
addServiceButtonText: '+ Add Service Notes (Optional)',
serviceNotes: [],
showServiceNotes: false,
showDeleteButton: true,
enteredServiceNote: '', //service notes addendum
}
},
computed : {
showServiceNotex(){
if(!this.showServiceNotes){
return '+Add Service Notes (Optional)'
}else{
return '- Remove Service Notes';
}
}
},
methods: {
setServiceNotes(){
this.showServiceNotes = !this.showServiceNotes;
},
addAnotherParty(){
this.validateForm();
if(this.counter === 0){
this.counter++;
this.lastElement = false;
}
if(!this.formIsValid){
return;
}
let emitObj = JSON.parse(JSON.stringify(this.partyInfo));
this.$emit('add-parties', emitObj); //event
},
deleteParty(){
this.$emit('delete-party');
},
validateForm(){
this.formIsValid = true;
if(this.partyInfo.fullName === ''){
this.validation.fullNameIsValid = false;
this.formIsValid = false;
}
if(this.partyInfo.serviceAddress === ''){
this.validation.serviceAddressIsValid = false;
this.formIsValid = false;
}
},
clearValidity(input){
this.validation[input] = true;
},
clearForm(){
this.partyInfo.fullName = '';
this.partyInfo.serviceAddress = '';
this.partyInfo.preAuthorize = false;
}
},
created(){
console.log('created');
}
}
</script>
附件是 <BaseCardList>
,它在 v-for
循环中呈现表单元素
BaseCardList.vue
<template>
<ul>
<base-card
v-for="(data, index) of partiesInfoList" :key="index"
ref="childComponent"
@add-parties="updatePartiesInfoList"
@delete-party="deleteParty(index)"
:lastElement="index === partiesInfoListLength - 1"
>
<!-- Wrapper for the `Parties Being Served` component-->
<template v-slot:title>
<slot></slot>
</template>
</base-card>
</ul>
</template>
<script>
import BaseCard from './BaseCard.vue';
export default {
components: { BaseCard },
data() {
return {
selectedComponent: 'base-card',
partiesInfoList : [
{id: 0,
fullName: 'dummy',
serviceAddress: 'dummy',
preAuthorize: ''
}
],
clearForm: false,
counter: 1
}
},
computed : {
hasParty(){
return this.partiesInfoList.length > 0;
},
partiesInfoListLength(){
return this.partiesInfoList.length;
}
},
methods: {
updatePartiesInfoList(additionalInfo){
// if(this.counter == 0){
// this.partiesInfoList.splice(0,1);
// }
this.partiesInfoList.push(additionalInfo);
this.counter++;
console.log(this.partiesInfoList);
console.log('The length of list is '+this.partiesInfoList.length);
},
deleteParty(resId){
// const resIndex = this.partiesInfoList.findIndex(
// res => res.id === resId
// );
// this.partiesInfoList.splice(resIndex, 1);
if(this.counter == 1){
return;
}
this.partiesInfoList.splice(resId, 1);
console.log('Index is '+resId);
console.log('after del');
console.log(this.partiesInfoList);
}
}
}
</script>
屏幕上的实际输出错误:相邻元素从 DOM 中删除。比如说,我点击 'Second' 的删除,但 'Third' 被删除了。但是,如果在 v-for 的末尾有一个空的表单元素,那么这个元素就会被删除。
在updatePartiesInfoList
中将新对象推送到partiesInfoList
之前,检查是否this.partiesInfoList[0].fullName === 'dummy'
returnstrue
,如果条件为真,则执行this.partiesInfoList.splice(0, 1)
从数组中删除虚拟对象!
您 v-for
中的键应该是一个 id,而不是一个索引。 Vue 将每个组件与其键相关联。
With keys, it will reorder elements based on the order change of keys, and elements with keys that are no longer present will always be removed/destroyed.
拼接 partyInfoList
项时,Vue 会重新注册索引。索引向下级联,并且由于 partyInfoList
中现在有 2 个项目而不是 3 个,索引为 2
或最后一个组件的 Vue 组件将被删除。
这是一个例子:
// partyInfoList
[
// index: 0
{
id: 0,
fullName: 'first',
serviceAddress: '1',
preAuthorize: ''
},
// index: 1
{
id: 1,
fullName: 'second',
serviceAddress: '2',
preAuthorize: ''
},
// index: 2
{
id: 2,
fullName: 'third',
serviceAddress: '3',
preAuthorize: ''
},
]
拼接
// resId = 1
this.partiesInfoList.splice(resId, 1);
结果数组
// partyInfoList
[
// index: 0
{
id: 0,
fullName: 'first',
serviceAddress: '1',
preAuthorize: ''
},
// index: 1
{
id: 2,
fullName: 'third',
serviceAddress: '3',
preAuthorize: ''
},
]
数组看起来不错,但屏幕上的模板却不行。这是因为 Vue 发现索引为 2
的 partyInfoList
项目不再存在,因此 :key="2"
的组件及其所有数据都被删除了 DOM。
你的解决方法其实很简单。您需要做的就是将 :key="index"
更改为 :key="data.id"
。这会将您的组件绑定到数据,而不是像索引这样的动态值。
我也不知道你是如何在每个 partyInfoList
项上设置 id
的,但是这些项必须是唯一的才能使键起作用。
你的新代码应该是这样的:
<base-card
v-for="(data, index) of partiesInfoList" :key="data.id"
ref="childComponent"
@add-parties="updatePartiesInfoList"
@delete-party="deleteParty(index)"
:lastElement="index === partiesInfoListLength - 1"
>
问题陈述:
我正在尝试设计一种涉及在每次 Add button
单击时复制 Parties Being Served
表单字段的设计。单击 Add Button
时,相应的 PartyInfo
对象将添加到 PartyInfoList
数组中
在BaseButtonList.vue文件中,我使用PartyInfoList
数组来设置v-for循环
<base-card
v-for="(data, index) of partiesInfoList" :key="index"
ref="childComponent"
@add-parties="updatePartiesInfoList"
@delete-party="deleteParty(index)"
:lastElement="index === partiesInfoListLength - 1"
>
但是,重要的是要注意最初数组没有元素。但是,由于我没有其他方法可以将数据输入到数组中,因此尽管 partiesInfoList
数组的元素为零,我还是不得不加载表单。我通过使用虚拟数据设置 partiesInfoList
来实现这一点。这允许显示初始表单。当 Add Another
按钮被点击时,第一个真正的条目将被推送到 partiesInfoList
.
但是,这会在从数组中删除条目时导致严重问题。当我控制台记录输出时,splice
确实正常运行。但是,Vue 最终从 DOM.
我使用了唯一的 index
密钥,也尝试了其他可能的密钥,但都产生了相同的有害错误。任何帮助将不胜感激。我认为这是一个非常棘手的设计模式,我可以想到更简单的替代方案,但我想让它成为一个挑战。也许我可以设置更好的数据流或其他东西。
附上代码
BaseCard.vue
<template>
//contains the template for the input form element
</template>
<script>
import { random } from '@amcharts/amcharts4/.internal/core/utils/String';
import { EventBus } from './bus.js';
export default {
emits:['add-parties','delete-party'],
props:['lastElement'],
data() {
return {
partyInfo:
{
id: '',
fullName: '',
preAuthorize: '',
serviceAddress: '',
},
validation: {
fullNameIsValid: true,
serviceAddressIsValid: true
},
hideAddButton: false,
formIsValid: true,
addServiceButtonText: '+ Add Service Notes (Optional)',
serviceNotes: [],
showServiceNotes: false,
showDeleteButton: true,
enteredServiceNote: '', //service notes addendum
}
},
computed : {
showServiceNotex(){
if(!this.showServiceNotes){
return '+Add Service Notes (Optional)'
}else{
return '- Remove Service Notes';
}
}
},
methods: {
setServiceNotes(){
this.showServiceNotes = !this.showServiceNotes;
},
addAnotherParty(){
this.validateForm();
if(this.counter === 0){
this.counter++;
this.lastElement = false;
}
if(!this.formIsValid){
return;
}
let emitObj = JSON.parse(JSON.stringify(this.partyInfo));
this.$emit('add-parties', emitObj); //event
},
deleteParty(){
this.$emit('delete-party');
},
validateForm(){
this.formIsValid = true;
if(this.partyInfo.fullName === ''){
this.validation.fullNameIsValid = false;
this.formIsValid = false;
}
if(this.partyInfo.serviceAddress === ''){
this.validation.serviceAddressIsValid = false;
this.formIsValid = false;
}
},
clearValidity(input){
this.validation[input] = true;
},
clearForm(){
this.partyInfo.fullName = '';
this.partyInfo.serviceAddress = '';
this.partyInfo.preAuthorize = false;
}
},
created(){
console.log('created');
}
}
</script>
附件是 <BaseCardList>
,它在 v-for
循环中呈现表单元素
BaseCardList.vue
<template>
<ul>
<base-card
v-for="(data, index) of partiesInfoList" :key="index"
ref="childComponent"
@add-parties="updatePartiesInfoList"
@delete-party="deleteParty(index)"
:lastElement="index === partiesInfoListLength - 1"
>
<!-- Wrapper for the `Parties Being Served` component-->
<template v-slot:title>
<slot></slot>
</template>
</base-card>
</ul>
</template>
<script>
import BaseCard from './BaseCard.vue';
export default {
components: { BaseCard },
data() {
return {
selectedComponent: 'base-card',
partiesInfoList : [
{id: 0,
fullName: 'dummy',
serviceAddress: 'dummy',
preAuthorize: ''
}
],
clearForm: false,
counter: 1
}
},
computed : {
hasParty(){
return this.partiesInfoList.length > 0;
},
partiesInfoListLength(){
return this.partiesInfoList.length;
}
},
methods: {
updatePartiesInfoList(additionalInfo){
// if(this.counter == 0){
// this.partiesInfoList.splice(0,1);
// }
this.partiesInfoList.push(additionalInfo);
this.counter++;
console.log(this.partiesInfoList);
console.log('The length of list is '+this.partiesInfoList.length);
},
deleteParty(resId){
// const resIndex = this.partiesInfoList.findIndex(
// res => res.id === resId
// );
// this.partiesInfoList.splice(resIndex, 1);
if(this.counter == 1){
return;
}
this.partiesInfoList.splice(resId, 1);
console.log('Index is '+resId);
console.log('after del');
console.log(this.partiesInfoList);
}
}
}
</script>
屏幕上的实际输出错误:相邻元素从 DOM 中删除。比如说,我点击 'Second' 的删除,但 'Third' 被删除了。但是,如果在 v-for 的末尾有一个空的表单元素,那么这个元素就会被删除。
在updatePartiesInfoList
中将新对象推送到partiesInfoList
之前,检查是否this.partiesInfoList[0].fullName === 'dummy'
returnstrue
,如果条件为真,则执行this.partiesInfoList.splice(0, 1)
从数组中删除虚拟对象!
您 v-for
中的键应该是一个 id,而不是一个索引。 Vue 将每个组件与其键相关联。
With keys, it will reorder elements based on the order change of keys, and elements with keys that are no longer present will always be removed/destroyed.
拼接 partyInfoList
项时,Vue 会重新注册索引。索引向下级联,并且由于 partyInfoList
中现在有 2 个项目而不是 3 个,索引为 2
或最后一个组件的 Vue 组件将被删除。
这是一个例子:
// partyInfoList
[
// index: 0
{
id: 0,
fullName: 'first',
serviceAddress: '1',
preAuthorize: ''
},
// index: 1
{
id: 1,
fullName: 'second',
serviceAddress: '2',
preAuthorize: ''
},
// index: 2
{
id: 2,
fullName: 'third',
serviceAddress: '3',
preAuthorize: ''
},
]
拼接
// resId = 1
this.partiesInfoList.splice(resId, 1);
结果数组
// partyInfoList
[
// index: 0
{
id: 0,
fullName: 'first',
serviceAddress: '1',
preAuthorize: ''
},
// index: 1
{
id: 2,
fullName: 'third',
serviceAddress: '3',
preAuthorize: ''
},
]
数组看起来不错,但屏幕上的模板却不行。这是因为 Vue 发现索引为 2
的 partyInfoList
项目不再存在,因此 :key="2"
的组件及其所有数据都被删除了 DOM。
你的解决方法其实很简单。您需要做的就是将 :key="index"
更改为 :key="data.id"
。这会将您的组件绑定到数据,而不是像索引这样的动态值。
我也不知道你是如何在每个 partyInfoList
项上设置 id
的,但是这些项必须是唯一的才能使键起作用。
你的新代码应该是这样的:
<base-card
v-for="(data, index) of partiesInfoList" :key="data.id"
ref="childComponent"
@add-parties="updatePartiesInfoList"
@delete-party="deleteParty(index)"
:lastElement="index === partiesInfoListLength - 1"
>