【问题标题】:For each results in v-for loop how can I nest another v-for loop using a parameter from the results of the first loop对于 v-for 循环中的每个结果,我如何使用第一个循环结果中的参数嵌套另一个 v-for 循环
【发布时间】:2019-09-03 09:31:39
【问题描述】:

在 Vue js 中使用 v-for 循环。我正在循环遍历readingTasks 数据对象,该对象正确地从下面的数据中产生了两个结果。

readingTasks:Array[2]
    0:Object
        enabled:true
        newunit:-1
        task:"The part 3 guide"
        unit:-1
        unit_task_id:27
        url:"#"
    1:Object
        enabled:true
        newunit:-1
        task:"The part 3 training units"
        unit:-1
        unit_task_id:28
        url:"#"

我不确定的是每个结果如何,我如何运行另一个Axios 数据库调用来显示读取任务是否完成。比如第一条记录,完整状态应该是真(unit_task_id:27),第二条记录应该是假。

userTasks:Array[1]
    0:Object
        complete:true
        enabled:true
        newunit:-1
        task:"The part 3 guide"
        unit:-1
        unit_task_id:27
        unit_task_user_id:21
<ul>
  <li v-for="task in readingTasks">
    {{task.task}} 

    //trying to call a function that does an Axios call passing in parameters from readingTasks 
    {{getUserTaskByUnit(task.unit, task.unit_task_id)}}
    <template v-for="usertask in userTasks">
      {{usertask.complete}}
    </template>
  </li>
</ul>
//javascript if its useful

data: {
    readingTasks: [],
    userTasks: []
},

mounted() {
    this.lastUnit();
},

methods: {

    //functons
    lastUnit: function() {

        this.tasks();

    },

    tasks: function() {
        var self = this;
        var unit = this.unit;


        axios.get("/WebService/units.asmx/GetTasks?unit=" + unit).then(function(response) {
            self.readingTasks = response.data;
        })
        .catch(function(error) {
            console.log(error);

        })
        .then(function() {


        });


    },

    getUserTaskByUnit: function(unit, unitTaskId) {

        var self = this;

        axios.get("/WebService/units.asmx/GetUserTasks?unit=" + unit + "&unitTaskId=" + unitTaskId).then(function(response) {
            self.userTasks = response.data;


        })
        .catch(function(error) {
            console.log(error);

        })
        .then(function() {});
    }

这段代码似乎接近于做正确的事情,但是{{usertask.complete}} 在两组结果的真假之间闪烁。就像被困在一个循环中一样。

我希望第一个结果在这里显示 True,而第二个结果显示 False。

第 3 部分指南 - 是的
第 3 部分训练单元 - 错误

【问题讨论】:

  • 你的userTasks来自哪里?
  • 它们通过 axios 调用来自 sql server 数据库:
  • axios.get("/WebServiceCall/units.asmx/GetUserTasks?unit=" + unit + "&unitTaskId=" + unitTaskId).then(function(response) { self.userTasks = response.data ;
  • 它们在一个单独的数据库表中用于读取任务
  • 尝试在 v-for 循环中从以下代码调用 userTasks:{{getUserTaskByUnit(task.unit, task.unit_task_id)}}

标签: vue.js vuejs2 axios


【解决方案1】:

这里有一些问题。

模板依赖于userTasks,所以每次userTasks发生变化都会导致组件重新渲染,再次运行模板。

模板每次运行时都会为这两个任务调用getUserTaskByUnit。这将异步更新userTasks。当userTasks更新时会触发重新渲染,会再次调用getUserTaskByUnit,无限循环。

比只是一个无限循环更糟糕的是,每次渲染都会触发两个请求,每个请求都会触发另一个重新渲染。请求的数量将呈指数级增长。

当这些请求确实返回时,您会将它们存储在 userTasks 中。但是两个响应都存储在完全相同的位置,因此您只能在 UI 中看到一个请求的结果。

您首先需要一个更好的数据结构来存储getUserTaskByUnit 中的响应。存储它们最简单的地方是readingTask 中的任务。这可能看起来像这样:

// Note the whole task is now being passed to getUserTaskByUnit
getUserTaskByUnit: function(task) {
    var self = this;

    axios.get("/WebService/units.asmx/GetUserTasks?unit=" + task.unit + "&unitTaskId=" + task.unit_task_id).then(function(response) {
        task.userTasks = response.data;
    })
    ...
}

getUserTaskByUnit 的调用需要移出模板。将它移入tasks 方法似乎和其他任何地方一样好。还需要进行一些更改才能使其与新版本的getUserTaskByUnit 一起使用:

tasks: function() {
    var self = this;
    var unit = this.unit;

    axios.get("/WebService/units.asmx/GetTasks?unit=" + unit).then(function(response) {
        var readingTasks = response.data;

        // Pre-populate userTasks so it will be reactive
        readingTasks.forEach(function(task) {
            task.userTasks = [];
        });

        // This must come after userTasks is pre-populated
        self.readingTasks = readingTasks;

        readingTasks.forEach(function(task) {
            // Passing task to getUserTaskByUnit, not unit and unit_task_id
            self.getUserTaskByUnit(task);
        });
    })
    ...

然后我们需要在模板中循环task.userTasks

<ul>
  <li v-for="task in readingTasks">
    {{task.task}} 
    <template v-for="usertask in task.userTasks">
      {{usertask.complete}}
    </template>
  </li>
</ul>

根据您的其他要求,我们可以使用其他数据结构。例如,您可以保留一个单独的userTasks 对象来保存userTasks,但要使其工作,它需要是一个嵌套数据结构而不仅仅是一个数组。您需要通过unit 键入它,然后unitTaskId。模板中的结果将是这样的:

<ul>
  <li v-for="task in readingTasks">
    {{task.task}} 
    <template v-for="usertask in userTasks[task.unit][task.unit_task_id]">
      {{usertask.complete}}
    </template>
  </li>
</ul>

与早期的解决方案非常相似,您需要在首次加载 readingTasks 时使用空值预填充 userTasks,以确保这些值是反应性的,并避免模板在 undefined 条目处爆炸。或者,您可以分别使用$set 和合适的v-if 检查。

这一切都非常繁琐。根据您对系统的了解,您可能可以稍微简化它。例如,可以为userTasks 形成复合字符串键,而不是使用两级嵌套。或者可能是 unit 是一个可以被认为是常量并且不需要包含在该数据结构中的道具。

【讨论】:

  • 非常感谢,skitlele 这是一个非常详细的答案,我现在可以使用它并且更好地了解 Vue 模板在渲染方面的工作原理。
【解决方案2】:

您的userTasks 是一个视图属性,每次调用getUserTaskByUnit 时都会被覆盖(即readingTasks 中的每个项目)。相反,您想要的是嵌套结构。一旦readingTasks 被加载,即在self.readingTasks = response.data; 行之后,您应该在循环中调用getUserTaskByUnit,并将响应存储为每个readingTask 对象的属性。

【讨论】:

  • 谢谢,这很有用。
猜你喜欢
  • 2022-06-25
  • 2018-07-27
  • 1970-01-01
  • 1970-01-01
  • 2013-08-04
  • 1970-01-01
  • 2014-03-21
  • 2020-04-04
  • 1970-01-01
相关资源
最近更新 更多