Arranging Objects and Arrays by Two Criteria

Extracting data from an API that provides information in the format below:

[
 {
  "id": 173,
  "date": "2020-12-10T16:05:30",
  "date_gmt": "2020-12-10T16:05:30",
  "guid": {},
  "modified": "2020-12-10T16:05:31",
  "modified_gmt": "2020-12-10T16:05:31",
  "slug": "test",
  "status": "publish",
  "type": "place",
  "link": "http://localhost:81/test/",
  "title": {},
  "content": {},
  "featured_media": 0,
  "template": "",
  "acf": {
    "address": {
    "address": "123 Test Address",
    "street_number": "123",
    "street_name": "Test Address",
    "city": "Philipsburg",
    "state": "Sint Maarten",
    "country": "Sint Maarten",
    "country_short": "SX"
  },
  "header": {}
  },
  "_links": {}
 },
 etc
]

Saving it in Vuex, and structuring the data with this approach:

computed: {
    resorts() {
      const resorts = {};
      if (this.$store.state.loading === false) {
        this.$store.state.posts.forEach((post) => {
          const c = post.acf.address.country;
          const s = post.acf.address.state;
          //const t = post.title;
          resorts[c] = resorts[c] || {};
          resorts[c][s] = resorts[c][s] || [];
          resorts[c][s].push(post);
        });
      }
      return resorts;
    },
}

Rendering the data in a v-for loop using Pug:

section.united-states(v-for="(country, index) in resorts" v-if="index==='United States'")
  h1(v-html="index")
  section.state(v-for="(state, subIndex) in country" :key="subIndex" :class="subIndex.toLowerCase()")
    h5(v-html="subIndex")
    ul
      li(v-for="post, resort) in state")
        listing(:id="post.id" :slug="post.slug" :image="post.acf.header" :title="post.title.rendered" :city="post.acf.address.city" :street="post.acf.address.street_name_short")

The current display is correct. However, I aim to sort it alphabetically by Country, followed by State, and then City names. I've experimented with sorting methods like lodash.orderBy, but was unable to achieve the desired organization. The Vue inspector reveals that countries and states (not cities) are listed alphabetically. Any suggestions?

Answer №1

If you're looking for a way to organize posts based on their address, one approach is to first sort the posts before grouping them.

To achieve this, you can utilize Array.prototype.sort() along with String.prototype.localeCompare(). You can create a utility function named sortPosts() that will help in sorting the posts by their country, state, city, and street_name fields:

const sortPosts = posts =>
  posts.slice().sort((a,b) => {
    const countryA = a.acf.address.country
    const countryB = b.acf.address.country
    const stateA = a.acf.address.state
    const stateB = b.acf.address.state
    const cityA = a.acf.address.city || '' 
    const cityB = b.acf.address.city || ''
    const streetA = a.acf.address.street_name
    const streetB = b.acf.address.street_name
    return countryA.localeCompare(countryB) || stateA.localeCompare(stateB) || cityA.localeCompare(cityB) || streetA.localeCompare(streetB)
  })

After sorting, you can then group these posts using similar logic but with a small tweak. Change the data type of the local variable resorts from Object to Map. This change is necessary because object iteration may not always maintain order, which could affect the sorting done by sortPosts():

export default {
  computed: {
    resorts() {
      const resorts = new Map();

      if (this.$store.state.loading === false) {
        sortPosts(this.$store.state.posts).forEach((post) => {
          const c = post.acf.address.country;
          const s = post.acf.address.state;

          if (!resorts.has(c)) {
            resorts.set(c, new Map());
          }
          const stateMap = resorts.get(c);
          if (!stateMap.has(s)) {
            stateMap.set(s, []);
          }
          stateMap.get(s).push(post);
        });
      }
      return resorts
    },
  }
}

Note that as of version 2.6.12, v-for does not directly support Maps. To work around this limitation, you can use Array.from() to make the Map iterable within the template using v-for:

<section v-for="[country, countryData] in Array.from(resorts)" :key="country">
  <h1 v-html="country" />
  <section class="state" v-for="[state, posts] in Array.from(countryData)" :key="state" :class="state.toLowerCase()">
    <h5 v-html="state" />
    <ul>
      <li v-for="(post, resort) in posts" :key="post.id">
        ...
      </li>
    </ul>
  </section>
</section>

You can check out a live demo for reference.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Extracting the magnifying glass from the picture

After implementing a function to add a magnifying glass (.img-magnifier-glass) on button click, I am now looking to remove the glass by clicking the "cancel" button. However, I am unsure of how to write this function to interact with the "magnify" function ...

The disappearing act of Redux state after being added to a nested array

When attempting to update my redux state, I am facing an issue where the state disappears. My approach involves checking for a parentId - if one exists, I insert the payload into the parent's children array. However, if no parentId is provided, I simp ...

Creating secure RSA keys using a predetermined seed - a step-by-step guide

Is it possible to utilize a unique set of words as a seed in order to recover a lost private key, similar to how cryptocurrency wallets function? This method can be particularly beneficial for end-to-end encryption among clients, where keys are generated o ...

Experiencing difficulties in transmitting images/files to API through reactjs and Material UI upload component

Recently, I tackled the task of creating an image upload component by utilizing an upload component from Material UI. While I have experience with this process using a simple HTML file input in the past, I found myself feeling a bit perplexed this time aro ...

How to align an image in the center of a circular flex container

I'm facing an issue in my Angular project where I have the following code snippet: onChange(event: any) { var reader = new FileReader(); reader.onload = (event: any) => { this.url = event.target.result; }; reader.readAsData ...

Adding elements to an array in Vue.js using a method

I'm facing a puzzling issue that has left me perplexed My registration form activates a method on blur for every input field; <input class='form-control' placeholder='Username' @blur="watchVal" v-model="username"> The Meth ...

Is there a way to detect the completion of the fadeout animation before calling a function?

I am trying to create a toast message using jQuery. When the "show" class is appended to the div, I want the toast message to fade in and then fade out after a few seconds. Once the fade-out animation is complete, I need to remove the "show" class. This ...

Unable to change the text with Jquery functionality

I currently have an iframe code that contains the word [UID]. My goal is to replace this word with a different word of my choosing. <iframe class="ofrss" src="https://wall.superrewards.com/super/offers?h=asacgrgerger&uid=[UID]" frameborder="0" widt ...

What are the benefits of removing event listeners in Reactjs?

In my opinion, the event listeners need to be reliable and consistent. React.useEffect(() => { const height = window.addEventListener("resize", () => { setWindowSize(window.innerHeight); }); return () => window.remov ...

Tips for enabling autoplay for videos in Owl Carousel

I am facing an issue with implementing autoplay functionality for videos in an owl carousel. Despite trying different solutions found online, including this Owl Carousel VIDEO Autoplay doesn’t work, I haven't been able to make it work. Additionally, ...

Array of JSON data passed in the request body

Recently, I have been attempting to pass JSON data to my req.body. The data structure is as follows: answers = ["A","B"]; //An array to be included in the JSON Object var Student_Answers = { //JSON object definition Answers: answers, matricNumber: ...

What could be causing the Logical Or to fail in my function?

How can I adjust the following sample code to check for not only empty keys but also null and undefined? I attempted: (obj[key] !== '' || obj[key] !== null || (obj[key] !== undefined) However, that approach caused issues and did not function c ...

Angular with Leaflet and Leaflet AwesomeMarkers error: "Attempting to access 'icon' property of undefined"

I'm attempting to integrate Leaflet Awesome Markers into my Angular 10 project to incorporate Font Awesome icons in my Leaflet markers. However, I'm running into an error when trying to create a L.AwesomeMarker. https://i.sstatic.net/7o81y.png ...

Issues with fundamental JavaScript client-side code

As a newcomer to the world of javascript and jQuery, I am diving into my first experiment with javascript. My initial focus has been on changing questions by clicking next or previous buttons. The goal is to create a dynamic quiz webpage that updates quest ...

Creating a progress bar feature using local storage in JavaScript

Is there a way to retain the progress of the countdown timer with a progress bar on page reload? Here is an example of what I am trying to achieve: https://codepen.io/Rudchyk/pen/qNOEGj <div id="progressBar"> <div class=& ...

Concealing option value based on ng-if conditions in AngularJS: A guide

I am designing an Input form with two input fields that need to be compared and values displayed if a certain condition is met. The input fields are: <td class="td_label"><label>Client Age :</label></td> <td class="td_input"> ...

Filtering DataGrid columns with an external button in Material-UI: A step-by-step guide

Imagine having a datagrid table structured as shown below: import * as React from 'react'; import { DataGrid, GridToolbar } from '@mui/x-data-grid'; import { useDemoData } from '@mui/x-data-grid-generator'; const VISIBLE_FIEL ...

Encountering an issue with getDerivedStateFromProps in React where an error states: Unable to retrieve property 'setState' of null

Just found out that componentWillReceiveProps is deprecated and now we should be using the getDerivedStateFromProps lifecycle method. You can find more information about it at this link. This is how I'm implementing it: class Main extends Component ...

What is the approach of Angular 2 in managing attributes formatted in camelCase?

Recently, I've been dedicating my time to a personal project centered around web components. In this endeavor, I have been exploring the development of my own data binding library. Progress has been made in creating key functionalities akin to those f ...

Modifying JavaScript prototypes on the fly can lead to troublesome issues

My curiosity has been piqued by the concept of dynamically changing a constructor's prototype in JavaScript, leading me to the findings above. It appears that an already constructed instance does not inherit the properties of the newly changed protot ...