Vuejs - 更新数组中 object 的数组
Vuejs - update array of an object which is in an array
我正在开发一个具有看板视图的帮助台工具。
我之前在我的后端使用了嵌套的序列化器,我设法让所有的东西都与一个查询一起工作,但是它不可扩展(而且很丑陋)所以我切换到另一个模式:
- 我查询我的服务台团队(屏幕截图中的'test')
- 我查询那个队的阶段('new','in progress')
- 我分阶段查询每个阶段的门票
所以当我安装我的组件时,我执行以下操作:
async mounted () {
if (this.helpdeskTeamId) {
await this.getTeam(this.helpdeskTeamId)
if (this.team) {
await this.getTeamStages(this.helpdeskTeamId)
if (this.stages) {
for (let stage of this.stages) {
await this.getStageTickets(stage)
}
}
}
}
},
其中 getTeam
、getTeamStages
和 getStageTickets
是:
async getTeam (teamId) {
this.team = await HelpdeskTeamService.getTeam(teamId)
},
async getTeamStages (teamId) {
this.stages = await HelpdeskTeamService.getTeamStages(teamId)
for (let stage of this.stages) {
this.$set(stage, 'tickets', [])
}
},
async getStageTickets (stage) {
const tickets = await HelpdeskTeamService.getTeamStageTickets(this.helpdeskTeamId, stage.id)
// tried many things here below but nothing worked.
// stage.tickets = stage.tickets.splice(0, 0, tickets)
// Even if I try to only put one :
// this.$set(this.stages[this.stages.indexOf(stage)].tickets, 0, tickets[0])
// I see it in the data but It doesn't appear in the view...
// Even replacing the whole stage with its tickets :
// stage.tickets = tickets
// this.stages.splice(this.stages.indexOf(stage), 1, stage)
},
在 getTeamStages
中,我将属性 'tickets' 添加到空列表的每个阶段。问题是当我查询每个阶段的所有门票时。我知道如何在带有拼接的数组中插入一个 object 或如何从数组中删除一个 object 但我不知道如何将整个数组分配给 [=63 的属性=] 在触发 Vue 反应性时位于数组中。在这里,我想将所有门票(这是一个列表)放入 stage.tickets
.
有可能实现吗?
如果不是,实现类似功能的正确设计是什么?
提前致谢!
编辑:
原来是模板部分产生了错误。我认为这不是根本原因,因为渲染了部分视图。我认为如果是这样的话,它会阻止渲染整个视图。但最后,在我的模板中,我有一部分正在执行 stage.tickets.length
,这在使用单个查询填充我的视图时有效。在使我的 API 更细化并独立于阶段查询票证时,有时 stage
没有 tickets
属性,直到我使用 this.$set(stage, 'tickets', [])
手动设置它。因此,模板停止呈现并引发问题。但是更新我的 stage.tickets
的方法在没有该模板问题的情况下也可以工作。
我可以反应性地更新阶段。这是我的完整代码;我使用了数组对象的 push
方法,它有效:
<template>
<div>
<li v-for="item in stages" :key="item.stageId">
{{ item }}
</li>
</div>
</template>
<script>
export default {
data() {
return {
stages: [],
};
},
methods: {
async getTeamStages() {
this.stages = [{ stageId: 1 }, { stageId: 2 }];
for (let stage of this.stages) {
this.$set(stage, "tickets", []);
}
for (let stage of this.stages) {
await this.getStageTickets(stage);
}
},
async getStageTickets(stage) {
const tickets = ["a", "b", "c"];
for (let ticket of tickets) {
this.stages[this.stages.indexOf(stage)].tickets.push(ticket);
}
},
},
mounted() {
this.getTeamStages();
},
};
</script>
需要注意的是,我使用了数组对象的concat
方法,也有效:
this.stages[this.stages.indexOf(stage)].tickets = this.stages[this.stages.indexOf(stage)].tickets.concat(tickets);
我尝试了您的方法,其中一些方法工作正常:
没用
this.$set(this.stages[this.stages.indexOf(stage)].tickets, tickets)
工作
this.$set(this.stages[this.stages.indexOf(stage)].tickets, 0, tickets[0]);
工作
stage.tickets = tickets
this.stages.splice(this.stages.indexOf(stage), 1, stage)
我确定是XY问题..
一个可能的解决方案是观察选定的团队并从那里加载值。您似乎正在从 mounted() 挂钩加载所有内容,我怀疑这实际上不会像您期望的那样按需加载所有内容。
我设法让它在这里工作,而无需求助于 $set 魔法,只是纯粹的旧传统 vue 魔法。 Vue 会注意到新对象的属性并自动使其成为响应式的,所以如果你稍后分配给它们,一切都会相应地响应。
我的设置是这样的(只显示相关部分)——凭记忆在这里打字,注意错别字:
data(){
teams: [],
teamId: null,
team: null
},
watch:{
teamId(v){
this.refreshTeam(v)
}
},
methods: {
async refreshTeam(id){
let team = await fetchTeam(id)
if(!team) return
//here, vue will auomaticlly make this.team.stages reactive
this.team = {stages:[], ...team}
let stages = await fetchStages(team.id)
if(!stages) return
//since this.team.stages is reactive, vue will update reactivelly
//turning the {tickets} property of each stage reactive also
this.team.stages = stages.map(v => ({tickets:[], ...v}))
for(let stage of this.team.stages){
let tickets = await fetchTickets(stage.id)
if(!tickets) continue
//since tickets is reactive, vue will update it accordingly
stage.tickets = tickets
}
}
},
async mounted(){
this.teams = fetchTeams()
}
请注意,我的“fetchXXX
”方法只会return从服务器检索的数据,而不会尝试实际设置组件数据
编辑:拼写错误
我正在开发一个具有看板视图的帮助台工具。
我之前在我的后端使用了嵌套的序列化器,我设法让所有的东西都与一个查询一起工作,但是它不可扩展(而且很丑陋)所以我切换到另一个模式:
- 我查询我的服务台团队(屏幕截图中的'test')
- 我查询那个队的阶段('new','in progress')
- 我分阶段查询每个阶段的门票
所以当我安装我的组件时,我执行以下操作:
async mounted () {
if (this.helpdeskTeamId) {
await this.getTeam(this.helpdeskTeamId)
if (this.team) {
await this.getTeamStages(this.helpdeskTeamId)
if (this.stages) {
for (let stage of this.stages) {
await this.getStageTickets(stage)
}
}
}
}
},
其中 getTeam
、getTeamStages
和 getStageTickets
是:
async getTeam (teamId) {
this.team = await HelpdeskTeamService.getTeam(teamId)
},
async getTeamStages (teamId) {
this.stages = await HelpdeskTeamService.getTeamStages(teamId)
for (let stage of this.stages) {
this.$set(stage, 'tickets', [])
}
},
async getStageTickets (stage) {
const tickets = await HelpdeskTeamService.getTeamStageTickets(this.helpdeskTeamId, stage.id)
// tried many things here below but nothing worked.
// stage.tickets = stage.tickets.splice(0, 0, tickets)
// Even if I try to only put one :
// this.$set(this.stages[this.stages.indexOf(stage)].tickets, 0, tickets[0])
// I see it in the data but It doesn't appear in the view...
// Even replacing the whole stage with its tickets :
// stage.tickets = tickets
// this.stages.splice(this.stages.indexOf(stage), 1, stage)
},
在 getTeamStages
中,我将属性 'tickets' 添加到空列表的每个阶段。问题是当我查询每个阶段的所有门票时。我知道如何在带有拼接的数组中插入一个 object 或如何从数组中删除一个 object 但我不知道如何将整个数组分配给 [=63 的属性=] 在触发 Vue 反应性时位于数组中。在这里,我想将所有门票(这是一个列表)放入 stage.tickets
.
有可能实现吗?
如果不是,实现类似功能的正确设计是什么?
提前致谢!
编辑:
原来是模板部分产生了错误。我认为这不是根本原因,因为渲染了部分视图。我认为如果是这样的话,它会阻止渲染整个视图。但最后,在我的模板中,我有一部分正在执行 stage.tickets.length
,这在使用单个查询填充我的视图时有效。在使我的 API 更细化并独立于阶段查询票证时,有时 stage
没有 tickets
属性,直到我使用 this.$set(stage, 'tickets', [])
手动设置它。因此,模板停止呈现并引发问题。但是更新我的 stage.tickets
的方法在没有该模板问题的情况下也可以工作。
我可以反应性地更新阶段。这是我的完整代码;我使用了数组对象的 push
方法,它有效:
<template>
<div>
<li v-for="item in stages" :key="item.stageId">
{{ item }}
</li>
</div>
</template>
<script>
export default {
data() {
return {
stages: [],
};
},
methods: {
async getTeamStages() {
this.stages = [{ stageId: 1 }, { stageId: 2 }];
for (let stage of this.stages) {
this.$set(stage, "tickets", []);
}
for (let stage of this.stages) {
await this.getStageTickets(stage);
}
},
async getStageTickets(stage) {
const tickets = ["a", "b", "c"];
for (let ticket of tickets) {
this.stages[this.stages.indexOf(stage)].tickets.push(ticket);
}
},
},
mounted() {
this.getTeamStages();
},
};
</script>
需要注意的是,我使用了数组对象的concat
方法,也有效:
this.stages[this.stages.indexOf(stage)].tickets = this.stages[this.stages.indexOf(stage)].tickets.concat(tickets);
我尝试了您的方法,其中一些方法工作正常:
没用
this.$set(this.stages[this.stages.indexOf(stage)].tickets, tickets)
工作
this.$set(this.stages[this.stages.indexOf(stage)].tickets, 0, tickets[0]);
工作
stage.tickets = tickets
this.stages.splice(this.stages.indexOf(stage), 1, stage)
我确定是XY问题..
一个可能的解决方案是观察选定的团队并从那里加载值。您似乎正在从 mounted() 挂钩加载所有内容,我怀疑这实际上不会像您期望的那样按需加载所有内容。
我设法让它在这里工作,而无需求助于 $set 魔法,只是纯粹的旧传统 vue 魔法。 Vue 会注意到新对象的属性并自动使其成为响应式的,所以如果你稍后分配给它们,一切都会相应地响应。
我的设置是这样的(只显示相关部分)——凭记忆在这里打字,注意错别字:
data(){
teams: [],
teamId: null,
team: null
},
watch:{
teamId(v){
this.refreshTeam(v)
}
},
methods: {
async refreshTeam(id){
let team = await fetchTeam(id)
if(!team) return
//here, vue will auomaticlly make this.team.stages reactive
this.team = {stages:[], ...team}
let stages = await fetchStages(team.id)
if(!stages) return
//since this.team.stages is reactive, vue will update reactivelly
//turning the {tickets} property of each stage reactive also
this.team.stages = stages.map(v => ({tickets:[], ...v}))
for(let stage of this.team.stages){
let tickets = await fetchTickets(stage.id)
if(!tickets) continue
//since tickets is reactive, vue will update it accordingly
stage.tickets = tickets
}
}
},
async mounted(){
this.teams = fetchTeams()
}
请注意,我的“fetchXXX
”方法只会return从服务器检索的数据,而不会尝试实际设置组件数据
编辑:拼写错误