Vuejs - 更新数组中 object 的数组

Vuejs - update array of an object which is in an array

我正在开发一个具有看板视图的帮助台工具。

我之前在我的后端使用了嵌套的序列化器,我设法让所有的东西都与一个查询一起工作,但是它不可扩展(而且很丑陋)所以我切换到另一个模式:

  1. 我查询我的服务台团队(屏幕截图中的'test')
  2. 我查询那个队的阶段('new','in progress')
  3. 我分阶段查询每个阶段的门票

所以当我安装我的组件时,我执行以下操作:

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)
        }
      }
    }
  }
},

其中 getTeamgetTeamStagesgetStageTickets 是:

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从服务器检索的数据,而不会尝试实际设置组件数据

编辑:拼写错误