2

I am iterating through a JSON object of the following type:

"entries": [{
    "first_name": "Brigitte",
    "last_name": "Bardot",
    "country": "Paris, France",
    "profession": "Actress"
  },
  {
    "first_name": "Apollo",
    "last_name": "AA",
    "country": "Witten, Germany",
    "profession": "Writer"
  }]

Using v-for and lodash I have an alphabetically ordered list of these entries:

<div v-for="user in orderedUsers" :key='user' class="user">
<p>{{ user.first_name }} {{ user.last_name }} ({{ user.country }}), {{ user.profession }}</p> 
</div>

I would like to create a header containing the first letter of the last name, in order to group the entries alphabetically as so:

A

Apollo

B

Bardot

etc..

The function I am using to sort through the entries is the following:

computed: {
      orderedUsers: function () {
        return orderBy(this.text[0].entries, 'last_name')
      }
    }

Any ideas on a simple and efficient way to achieve this?

ogot
  • 341
  • 2
  • 17

3 Answers3

5

Order the entries by last_name, and group by the 1st letter of each user. Iterate the items with flatMap, and add the keys (the last name) letter.

In vue use v-if (the item is a string) and v-else to decide to render the item or the title.

const { flow, orderBy, groupBy, flatMap, get } = _
const entries = [{"first_name":"Brigitte","last_name":"Bardot","country":"Paris, France","profession":"Actress"},{"first_name":"Apollo","last_name":"AA","country":"Witten, Germany","profession":"Writer"}]
  
const groupItems = flow([
  arr => orderBy(arr, 'last_name'),
  arr => groupBy(arr, o => get(o, 'last_name[0]', '').toUpperCase()),
  groups => flatMap(groups, (v, k) => [
    k,
    ...v
  ])
])

new Vue({
  el: '#app',
  data: { orderedUsers: groupItems(entries) }
})
/** hide the annoying vue production messages **/
.as-console-wrapper {
  display: none !important;
}
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.13/dist/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>

<div id="app">
  <div v-for="item in orderedUsers">
    <h2 v-if="typeof item === 'string'">
      {{ item }}
    </h2>
      <p v-else>{{ item.first_name }} {{ item.last_name }} ({{ item.country }}), {{ item.profession }}</p> 
  </div>
</div>
Ori Drori
  • 183,571
  • 29
  • 224
  • 209
0

Came up with the following solution in the interim, but I believe Ori Dori's answer is simpler.

let users = orderBy(this.text[0].entries, 'last_name');

    const map1 = users.map(x => x.last_name.substring(0,1));

    const letters = map1.filter(function(item, index){
  return map1.indexOf(item) >= index;
});

const groups = {};

// create groups containers from names
letters.forEach(k => {
  groups[k] = []
});

 users.forEach(k => {
  const user = k.last_name.substring(0,1)
  groups[user].push(k)
})

  return groups
ogot
  • 341
  • 2
  • 17
0

Digging out old question for anyone that doesn't want to use lodash.

This solution uses object instead of array of objects, so there is some nested looping involved in html. Still better than importing lodash for one usage imo.

js:

data = [
  {
      "name": "some name",
      "description": "aaa"
  },
  {
      "name": "a different name",
      "description": "a"
  }
]

sortData(data) {
   let groupedData = {}
   data.forEach( entry => {
     if (!Object.keys(groupedData).includes(entry.name[0]))
        groupedData[`${entry.name[0]}`] = []
     groupedData[`${entry.name[0]}`].push(entry)
     })
   this.dictionaryData = groupedData
   }

vue html:

 <div v-for="(section , index) in dictionaryData" :key="index">
    <div>
      <h2>{{ index.toUpperCase() }}</h2>
    </div>
    <span v-for="(item, index) in section" :key="index">
      <div>
        <h3>
          {{item.name}}
        </h3>
        <p>{{item.description}}</p>
      </div>
    </span>
  </div>
Izabela
  • 1
  • 1
  • 1
    As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community May 25 '23 at 22:51