[Vuejs]-Iterate an object -> array -> object with Vue JS Typescript

0👍

<div class="openingHours d-flex flex-wrap mb-10" v-for="(item, index) in foodMerchant.opening_hours.data" :key="index">
  <div class="d-flex justify-content-between mb-10 w-100">
    <h5 class="font-italic text-black font-12">
      {{ weeks[item.day - 1] }}
    </h5>

    <h5 class="font-italic text-black font-12 font-weight-light">
      {{ item.startTime }} - {{ item.endTime }}
    </h5>
  </div>
</div>
<script>
    export default {
        data() {
            return {
                weeks: ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
            }
        }
    }
</script>

hope it helps

0👍

Here’s a sketch of how I might solve it (I haven’t tested the code, sorry):

Template:

<button @click="showOpeningHours = !showOpeningHours">show opening hours</button>

<div class="openingHours d-flex flex-wrap mb-10"
     v-if="showOpeningHours"
     v-for="item in foodMerchant.opening_hours.data">
  <div class="d-flex justify-content-between mb-10 w-100">
    <h5 class="font-italic text-black font-12">
      {{ formatDay(item.day) }}
    </h5>

    <h5 class="font-italic text-black font-12 font-weight-light">
      {{ formatTime(item.startHour, item.startMinute, item.startSecond) }}
      -
      {{ formatTime(item.endHour, item.endMinute, item.endSecond) }}
    </h5>
  </div>
</div>

Component:

import {
  Vue,
  Component
} from 'vue-property-decorator';
import {
  namespace
} from 'vuex-class';
import FoodMerchant from '../../models/FoodMerchant';

const WEEKDAYS = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday',
                  'Friday', 'Saturday'];

export default class MerchantProfilePage extends Vue {
  @namespace('merchant').State('foodMerchant') foodMerchant!: FoodMerchant;
  private showOpeningHours: boolean = false;

  private formatDay(day: number): string {
    return WEEKDAYS[Math.trunc(day) % 7]
  }

  private formatTime(h: number; m: number, s: number): string {
    // It's better to use a library for this
    // The Date constructor needs a full date, but we'll only use the time
    const date = new Date(`2000-01-01 ${h}:${m}:${s}`)
    return date.toLocaleTimeString('en-us');
  }
}

Your questions were:

  • Do i use string interpolation?
  • Am i supposed to use the v-for directive inside the .vue page instead to display the data?

I think you’ve correctly identified the main problems you’re facing: how to display all the items, and how to format them.

As you can see, v-for is a neat way to show different kinds of lists without repeating yourself.

Formatting is a bigger topic, there are many ways to do it. The code I included above kind of works but it’s mostly there as an example. You might want to consider these things:

  • Vue filters could allow you to define the formatting in a single place and write code like this {{ item.startTime | formatTime }}
  • Use a library to help you formatting things. Dates can be tricky, especially when you need to support different locales etc. There are a lot of them – I’ve used date-fns, luxon and Moment. They all have different pros and cons.
  • If you control the format of the data, you could make sure it’s easy to format, ie can be parsed and formatted with the library you picked without modifying it first.

Finally, I think your question is a bit too broad for the Stack Overflow format, since an answer might not help anyone but you. On the other hand, you’ve made a good effort to show what you’ve tried and how you’re thinking. Looking at your code, it looks like you know what you’re doing but you’re just missing a few of the tools. If you haven’t already, maybe skim through the main sections of the Vue Guide. There are lots of examples. Even if you don’t understand everything at once it’s good to have an idea of what’s possible.

Leave a comment