从v-for循环中计算多个总数

时间:2018-09-19 02:31:55

标签: vue.js v-for

我有一个独特的情况,我有一个用户的v-for循环(Staff),而在里面,我有另一个v-for循环来检查用户积累的休假。

所以简单地说

v-for get user
    //Print users name
    v-for get any leave associated with this user
          //Print that days Annual Leave
          //Print that days Sick Leave
    v-end
    //Print total Annual Leave
    //Print total Sick Leave
v-end

请假数据库的内容具有这些值

类型:(病假,年假,丧亲等) 时间:整数

所以基本上它会说

Thomas               Annual        Sick
------------------------------------------
Annual Leave         2 hours       0 Hours
Sick Leave           0 Hours       3 Hours
Annual Leave         4 Hours       0 Hours
-------------------------------------------
Total                6 Hours       3 Hours

John                 Annual        Sick
------------------------------------------
Annual Leave         2 hours       0 Hours
Annual Leave         2 Hours       0 Hours
-------------------------------------------
Total                4 Hours       0 Hours

现在输入代码和到目前为止的内容:

<div v-for="user_list in user_list_filtered()">
   <div class="user_heading"><h2>{{ user_list.first_name }}</h2></div>
   <div class="report_content" v-for="userleave in user_leave_filtered(user_list['.key'])">
      <div class="leave_type_content">
         {{ userleave.type }}
      </div>
      <div class="days_taken_content">
         //Get Leave
      </div>
      <div class="lsl_content">
         //Get Sick Leave
      </div>
   </div>
   <div class="leave_content">
      <div class="total_leave_title">
         Total Leave Taken
      </div>
      <div class="total_hours">
         // Print Total Leave
      </div>
      <div class="total_hours">
         //Print Total Sick Leave
      </div>
   </div>
</div>

因此,如果它是病假类型,则将其添加到第二列,并将第一列设置为0,或者如果!==病假,将第一列设置为value,第二列设置为0。

我已经尝试过将某些功能用作函数,但是却遇到了无限循环,因此我很困惑,因为大多数帖子并不像我想要实现的那样复杂。

感谢您的帮助

编辑: 附加功能

user_leave_filtered(userPassed) {
  var self = this
  return this.userLeave.filter(function (i) {
    if (i.users_id === userPassed &&
      ((i.start_time >= self.getUnix(self.firstDate) && i.start_time <= self.getUnix(self.lastDate)) ||
        (self.firstDate === null || self.firstDate === '' || self.lastDate === null || self.lastDate === ''))) {
      return true
    } else {
      return false
    }
  })
},
user_list_filtered() {
  var self = this

  return this.userList.filter(function (i) {

    var passed = false

    if (self.userToShow === i['.key'] || self.userToShow === 'All') {
      // Track whether to filter out this leave or not
      self.userLeave.forEach(function (element) {
        if (element.users_id === i['.key']) {
          passed = true
        } else {}
      })
    }

    return passed
  })
},

2 个答案:

答案 0 :(得分:2)

第一条经验法则,不要在HTML中调用函数。改用 computed properties

您可以获得过滤的用户列表,并map列出每个用户所需的数据。

无论如何,我建议您在后端处理“用户离开”的映射,并使数据尽可能接近客户端中使用的数据。

这是我如何处理您的案例的示例(请注意,由于您未在问题中提供完整的代码,因此我没有使用可能使用的相同对象结构)

new Vue({
  el: "#app",
  data: {
    userList: [
      { id: 1, firstName: "Jon Doe" },
      { id: 2, firstName: "Jane Doe" }
    ],
    userLeave: [
      { userId: 1, type: "anual", hours: 2 },
      { userId: 1, type: "sick", hours: 3 },
      { userId: 1, type: "anual", hours: 4 },
      { userId: 2, type: "anual", hours: 2 },
      { userId: 2, type: "sick", hours: 3 },
      { userId: 2, type: "anual", hours: 4 }
    ]
  },
  computed: {
    usersById () {
      if (!this.userList.length) return null;
      // create a list of users by id and save a few iterations
      return this.userList.reduce((list, user) => {
        list[user.id] = user;
        return list  
      }, {})
    },
    filteredUsers () {
      if (!this.userLeave.length) return [];
      const users = {}
      this.userLeave.forEach(leave => {
        const user = this.usersById[leave.userId]
        if (user) {
          if (leave.type === "sick") {
            user.totalSick = typeof user.totalSick === "number"
              ? leave.hours + user.totalSick
              : leave.hours;
          } else {
            user.totalAnual = typeof user.totalAnual === "number"
              ? leave.hours + user.totalAnual
              : leave.hours;
          }
          if (user.leaves === undefined) user.leaves = []
          user.leaves.push(leave)
          users[user.id] = user
        }
      })
      return users
    }
  }
})
.leave_type_content,
.days_taken_content,
.lsl_content,
.total_leave_title,
.total_hours,
.total_hours {
  display: inline-block
}
<script src="https://unpkg.com/vue@2.5.17/dist/vue.min.js"></script>
<div id="app">
  <div v-for="user in filteredUsers"> <!-- NOTICE THE COMPUTED PROPERTY -->
   <div class="user_heading"><h2>{{ user.firstName }}</h2></div>
   <div class="report_content" v-for="userleave in user.leaves">
      <div class="leave_type_content">
         {{ userleave.type }}
      </div>
      <div class="days_taken_content">
         {{ userleave.type === "anual" && userleave.hours || 0 }} hours
      </div>
      <div class="lsl_content">
         {{ userleave.type === "sick" && userleave.hours || 0 }} hours
      </div>
   </div>
   <div class="leave_content">
      <div class="total_leave_title">
         Total Leave Taken
      </div>
      <div class="total_hours">
         {{ user.totalAnual }}
      </div>
      <div class="total_hours">
         {{ user.totalSick }}
      </div>
   </div>
</div>
</div>

答案 1 :(得分:1)

我将创建一个计算属性,该属性包含要显示的用户及其映射的休假和总数。例如

computed: {
  usersWithLeave () {
    const unixFirstDate = this.firstDate && this.getUnix(this.firstDate)
    const unixLastDate = this.lastDate && this.getUnix(this.lastDate)
    // first map the leave entries by user for quick access
    const leaveByUser = this.userLeave.reduce((map, element) => {
      // Filter out by dates
      if (
          (!unixFirstDate || element.start_time >= unixFirstDate) &&
          (!unixLastDate || element.start_time <= unixLastDate)
      ) {
        const elements = map.get(element.users_id) || []
        elements.push(element)
        map.set(element.users_id, elements)  
      }
      return map
    }, new Map())

    // now construct a filtered array of users then map to one with leave attached
    return this.userList
        .filter(({'.key': id}) => [id, 'All'].includes(this.userToShow) && leaveByUser.has(id))
        .map(({'.key': id, first_name}) => {
          const leave = leaveByUser.get(id)
          return {
            first_name,
            leave, // an array of all leave elements
            totals: leave.reduce((totals, element) => {
              totals[element.type === 'Sick Leave' ? 'sick' : 'annual'] += element.Hours
              return totals
            }, { sick: 0, annual: 0 })
          }
        })
  }
}

哇,那是比预期更多的工作。这将产生一系列看起来像

的对象
{
  first_name: 'Thomas',
  leave: [
    { type: 'Annual Leave', Hours: 2 },
    { type: 'Sick Leave', Hours: 3 },
    { type: 'Annual Leave', Hours: 4 }
  ],
  totals: {
    sick: 3,
    annual: 6
  }
}

现在您可以轻松地在模板中使用它

<div v-for="user in usersWithLeave">
  <div class="user_heading"><h2>{{ user.first_name }}</h2></div>
  <div class="report_content" v-for="userleave in user.leave">
      <div class="leave_type_content">
        {{ userleave.type }}
      </div>
      <div class="days_taken_content">
        {{ userleave.type !== 'Sick Leave' && userleave.Hours || 0 }}
      </div>
      <div class="lsl_content">
      {{ userleave.type === 'Sick Leave' && userleave.Hours || 0 }}
      </div>
  </div>
  <div class="leave_content">
      <div class="total_leave_title">
        Total Leave Taken
      </div>
      <div class="total_hours">
        {{ userleave.totals.annual }}
      </div>
      <div class="total_hours">
        {{ userleave.totals.sick }}
      </div>
  </div>
</div>