Geoff_S
Geoff_S

Reputation: 5105

V-for/V-if loop on a multi-level array and matching by date

I'm having an issue trying to figure out a v-for loop around an array that I've built, which is in the exact format that I want

The snippet below shows the format of the data, but basically I'm trying to build a table for employees where the table header is made of dates and the employee data is matched by the date.

My issue is that I can't figure out how to loop down to the jobs level and match the data for each table cell to the date in the header

Given the array dumped in the snippet below, I would want something like this:

Employee  |  08/12/2021            |  08/13/2021
----------------------------------------------------------------
Miranda   | Area 1234567           |  Area 1234569
              Job 123 - 10 Hours        Job 184 - 18 Hours
            Area 1234568
              Job 167 - 15 Hours

So basically just matching the array records by employee and date (in table header), and then where there's a match just display the area/job information in the table cell

How can I fix the current v-for loop structure I've started in order to achieve this?

const nest = (rows) =>
  rows .reduce(
    (a, row) => {
      const employee = a [row .employee] || (a [row .employee] = {dates: {}})
      const date = employee .dates [row .job_date] || (employee .dates [row .job_date] = {areas: {}})
      const order = date .areas [row .area_number] || (date .areas [row .area_number] = {jobs: {}})
      const job = order .jobs [row .job] || (order .jobs [row .job] = {hours: '', scans: '', job_date: ''})

      job.hours += row.hours
      job.scans += row.scans
      job.job_date = row.job_date

      return a
    },
    {}
  );

new Vue({
  el: "#app",
  props: { 

  },
  data: {
    rows: [
        {  
            employee: "Miranda",
            job: "123",
            hours: "10",
            job_date: "08/12/2021",
            scans: 37,
            area_number: "1234567",

        },
         {  
            employee: "Miranda",
            job: "167",
            hours: "15",
            scans: 12,
            job_date: "08/12/2021",
            area_number: "1234568",
            
        },
        {  
            employee: "Miranda",
            job: "184",
            hours: "18",
            scans: 24,
            job_date: "08/13/2021",
            area_number: "1234569",
            
        }
    ],
},
computed: {

    numbersByEmployee() { 
      return nest(this.rows)
    },
    dates() {
      const dates = [...new Set(this.rows.map(r => r.job_date))]
      return dates.sort((a,b) => new Date(a) - new Date(b))
    },
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>


<div id="app">

  <table>
  <thead>
      <tr>
       <th>Employee</th>
          <th v-for="date in dates" :key="date">{{ date }}</th>
      </tr>
    </thead>
  <tbody>
    <tr v-for="(areas,employee) in numbersByEmployee" :key="employee">
      <td>{{employee}}</td>
      <td v-for="date in dates" :key="date">
        
      </td>
    </tr>
  </tbody>
  </table>


{{numbersByEmployee}}
</div>

Upvotes: 2

Views: 496

Answers (1)

Nitheesh
Nitheesh

Reputation: 20006

Just like array, you can also apply v-for to objects. Reference

Syntax

v-for="(value, key) in object"

Working Solution

const nest = (rows) =>
  rows.reduce(
    (a, row) => {
      const employee = a[row.employee] || (a[row.employee] = { dates: {} })
      const date = employee.dates[row.job_date] || (employee.dates[row.job_date] = { areas: {} })
      const order = date.areas[row.area_number] || (date.areas[row.area_number] = { jobs: {} })
      const job = order.jobs[row.job] || (order.jobs[row.job] = { hours: '', scans: '', job_date: '' })

      job.hours += row.hours
      job.scans += row.scans
      job.job_date = row.job_date

      return a
    },
    {}
  );

new Vue({
  el: "#app",
  props: {

  },
  data: {
    rows: [
      {
        employee: "Miranda",
        job: "123",
        hours: "10",
        job_date: "08/12/2021",
        scans: 37,
        area_number: "1234567",

      },
      {
        employee: "Miranda",
        job: "167",
        hours: "15",
        scans: 12,
        job_date: "08/12/2021",
        area_number: "1234568",

      },
      {
        employee: "Miranda",
        job: "184",
        hours: "18",
        scans: 24,
        job_date: "08/13/2021",
        area_number: "1234569",

      }
    ],
  },
  computed: {

    numbersByEmployee() {
      return nest(this.rows)
    },
    dates() {
      const dates = [...new Set(this.rows.map(r => r.job_date))]
      return dates.sort((a, b) => new Date(a) - new Date(b))
    },
  }
});
td,
th {
  border: 1px solid black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  <table>
    <thead>
      <tr>
        <th>Employee</th>
        <th v-for="date in dates" :key="date">{{ date }}</th>
      </tr>
    </thead>
    <tbody>
      <tr v-for="(value, name) in numbersByEmployee" :key="name">
        <!-- name will be Miranda-->
        <!-- Value will be dates object-->
        <td>{{name}}</td>
        <td v-for="(dateSpecificData, dateValue) in value.dates" :key="dateValue">
          <div v-for="(areaList, areaKey) in dateSpecificData">
            <div v-for="(area, areaId) in areaList">
              Area {{ areaId }}
              <div v-for="(job, jobId) in area.jobs">
                Job {{ jobId }} - {{job.hours}} Hours
              </div>
            </div>
          </div>
        </td>
      </tr>
    </tbody>
  </table>
</div>

Upvotes: 1

Related Questions