Iterate over a Vue.js dynamic array and place each object component into individual divs within a separate component based on a specific value associated with each object

I'm currently developing a Vue app that showcases company offices categorized by regions. My setup includes a main home view, an offices component, and an office item component. Utilizing v-for in the offices component allows me to iterate through the office items and display them successfully. However, I face a challenge when attempting to sort the office items into distinct divs based on the "Region" value, which spans across 5 regions.

While I understand how to import components into one another, my struggle lies in looping through all the office items within the offices component. My intuition suggests implementing a loop within a loop, but I wonder if there's a missing component in this equation?

office item component:

<div class="office" :class="office.Region">
  <p>{{office.Name}}</p>
  <p>{{office.Address}}</p>
  <p>{{office.Country}}</p>
  <p>{{office.Region}}</p>
  <p>{{office.Email}}</p>
  <p>{{office.Phone}}</p>
</div>

offices component:

<div>
  <div v-for="office in offices" :key="office.name">
    <div class="office-container global" v-if="office.Region === 'Global'">
      <ul>
        <li><OfficeItem v-bind:office="office"/></li>
      </ul>
    </div>
    <div class="office-container north" v-if="office.Region === 'North America'">
      <ul>
        <li><OfficeItem v-bind:office="office"/></li>
      </ul>
    </div>
    <div class="office-container europe" v-if="office.Region === 'Europe, Middle East and Africa'">
      <ul>
        <li><OfficeItem v-bind:office="office"/></li>
      </ul>
    </div>         
    <div class="office-container asia" v-if="office.Region === 'Asia Pacific'">
      <ul>
        <li><OfficeItem v-bind:office="office"/></li>
      </ul>
    </div>
    <div class="office-container latin" v-if="office.Region === 'Latin America'">
      <ul>
        <li><OfficeItem v-bind:office="office"/></li>
      </ul>
    </div>
  </div>
</div>

a hardcoded array of objects:

offices: [
    {
      Name: "Corporate Headquarters",
      Address: "Suite 500, 698 West 10000 South, South Jordan, Utah 84095",
      Country: "USA",
      Region: "Global",
      Email: "<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="5d3e3233293c3e291d342b3c332934733e3230">[email protected]</a>",
      Phone: "+1-888-253-6201"
    },
    {
      Name: "EMEA Headquarters",
      Address: "First Floor Europa House, Harcourt Street Dublin 2, D02 WR20",
      Country: "Ireland",
      Region: "Europe, Middle East and Africa",
      Email: "<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="caa9a5a4bebaaabfaaaeb7a8abbab0adaae6aba7a5">[email protected]</a>",
      Phone: "+ 353 1 411 7100"
    },
    {
      Name: "India",
      Address: "Bagmane Tech Park, Unit No. 4A, Level 2 , Bangalore",
      Country: "India",
      Region: "Asia Pacific",
      Email: "<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="593a36372d383a2d193129393236733e3032">[email protected]</a>",
      Phone: ""
    },
    {
      Name: "Brazil",
      Address: "Borges de Figueiredo, 303 - 4th floor, Bairro Mooca, São Paulo, SP 03110-010",
      Country: "Brazil",
      Region: "Latin America",
      Email: "<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="32515d5c465351461f51434c5359404954564b59125f5351">[email protected]</a>",
      Phone: "+55 11 9 8136 0343"
    },
    {
      Name: "United States (Seattle)",
      Address: "1011 Western Ave SW #700, Seattle, WA 98104",
      Country: "United States",
      Region: "North America",
      Email: "<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="24474b4a50454750644542477a5d40484248454fc4924f434550">[email protected]</a>",
      Phone: "+1-206-274-4280"
    }
]

I aim for only 5 office-container divs containing corresponding office listings. However, the issue at hand is multiple occurrences of office-container (like two North America divs) with additional empty divs nested inside.

Answer №1

Extracting all regions from your list of offices is made simple with

[...new Set(this.offices.map(o => o.Region))]
.

To display offices by region, you can create a filtering method:

officesOfRegion(region) {
  return this.offices.filter(o => o.Region === region)
},

Vue.config.productionTip = false;
Vue.config.devtools = false;

new Vue({
  el: '#hook',
  template: '#appTemplate',
  data: ({
    offices: [{...
    
      ...
      
    ]
  }),
  computed: {
    regions() {
      return [...new Set(this.offices.map(o => o.Region))]
    }
  },
  methods: {
    officesOfRegion(region) {
      return this.offices.filter(o => o.Region === region)
    },
    displayJson(o) {
      return JSON.stringify(o, null, 2);
    }
  },

})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script type="text/template" id="appTemplate">
  <div id="app">
    <div class="region" v-for="region in regions" :key="region">
      <hr>
      <h3 v-text="region"></h3>
      <ul>
        <li v-for="(office, i) in officesOfRegion(region)" :key="i">
          <pre v-html="displayJson(office)"></pre>
        </li>
      </ul>
    </div>
  </div>
</script>
<div id="hook"></div>

Your markup structure doesn't restrict how this information is presented. Feel free to customize it as needed.

And here’s the code snippet integrated with your markup for reference:

Vue.config.productionTip = false;
Vue.config.devtools = false;

new Vue({
  el: '#hook',
  template: '#appTemplate',
  data: ({...
  
  ...
  
}),
computed: {...
methods: {
propsOf(o) {
return Object.keys(o);
}
},

})
.office p {
  display: flex;
}
.office p strong {
  width: 100px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script type="text/template" id="appTemplate">
  <div id="app">
    <div class="region" v-for="region in regions" :key="region">
      <hr>
      <hr>
      <h3>{{region}}</h3>
      <div v-for="(office, i) in officesOfRegion(region)" :key="i" class="office">
        <hr>
        <p v-for="prop in propsOf(office)"><strong>{{prop}}:</strong> {{office[prop]}}</p>
      </div>
    </div>
  </div>
</script>
<div id="hook"></div>

Answer №2

It appears that the only thing changing in your template is the classes surrounding the OfficeItem Component.

To prevent repetition in your code, consider implementing the conditional logic inside the OfficeItem Component as shown below:

// OfficeItem.vue
<template>
  <li :class="['office-container', getRegionClass(office.Region)]">{{office.Region}}</li>
</template>

<script>
const regional_classes = {
  A: 'class_a and-another-A-class',
  B: 'class_b and-another-B-class',
  C: 'class_c and-another-C-class',
  D: 'class_d and-another-D-class',
  Z: 'class_z and-another-Z-class'
}

export default {
  name: "OfficeItem",
  props: {
    office: Object
  },
  methods: {
    getRegionClass(region) {
      return regional_classes[region] || ''
    }
  }
};
</script>
Alternatively, you could use a switch statement to determine the appropriate class based on the Region.

In this case, I believe utilizing a regional_class Object is more readable and maintainable.

In your Offices component, simply pass the office object to your Officeitem like so:

// Offices.vue
<template>
  <div>
    <ul :key="`${regionName}_${index}`" v-for="(region, regionName, index) in officesByRegion">
      <h1>Region {{regionName}}</h1>
      <OfficeItem v-for="office in region" :key="office.Region" :office="office"/>
    </ul>
  </div>
</template>

<script>
export default {
  name: "Offices",
  data() {
    return {
      offices: [
        { Region: "A" },
        { Region: "B" },
        { Region: "C" },
        { Region: "D" },
        { Region: "Z" },
        { Region: "A" },
        { Region: "B" },
        { Region: "A" },
        { Region: "B" },
        { Region: "A" },
        { Region: "Z" },
        { Region: "C" },
        { Region: "D" },
        { Region: "E" }
      ]
    };
  },
  computed: {
    officesByRegion() {
      const obj = {};
      this.offices.forEach(o => {
        if (o.Region in obj) obj[o.Region].push(o);
        else obj[o.Region] = [o];
      });
      return obj;
    }
  }
};
</script>

I trust this will be beneficial in understanding dynamic css class application. :-)

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

Node and Web scraping Promise: a powerful combination

I've been using Cheerio and Node for web scraping, and I thought implementing promises could simplify handling asynchronous code. However, my attempt to chain promises hasn't been successful. Below is the code I'm working with, in hopes that ...

Creating a button that includes a link and a variable

I'm attempting to create a button that redirects me to another page, but I'm having trouble including a variable in the link. Here's my script: $idSelect[i]="SELECT * FROM times WHERE id=" . $mid[i] . ""; $idResult[i]=mysqli_query($con,$id ...

How to effectively modify a worldwide array within a recursive function

I am currently enrolled in an algorithms MOOC and am working on a small program that calculates the number of inversions in an array A consisting of integers in arbitrary order. An inversion occurs when a pair (i,j) of indices in the array satisfy i<j a ...

Anomaly observed in the deconstruction of Material UI table components

Utilizing the table component from the Material UI react components library, I encountered a need to incorporate custom behavior into the TableRow. To achieve this, my approach involved breaking down the table and planning to encapsulate it within my own ...

Guide to making a dynamic hyperlink in VueJS using filtered or modified data

I am developing a VueJS application that receives data in the following format: data: function() { return { posts: ['1:foo bar oof rab', '2:bar oof rab foo', '3:oof rab foo bar'] } } My goal is to create a template t ...

It is essential for Jquery to properly evaluate the first JSON result, as skipping

I'm currently facing an issue where the first JSON result is being skipped when I try to evaluate a set of JSON results. Below is the Jquery code snippet in question: function check_product_cash_discount(total_id){ //check for cash discount ...

Concealing a navigation tab with Angular4 in Typescript: A tutorial

I have successfully implemented 3 tabs in my Angular 4 project. At the moment, I am focusing on working with the first two tabs and planning to tackle the third tab in the near future. To keep things clean and organized, I am looking to use JavaScript/Typ ...

embedding JSON data into the main template

I'm looking to include a JSON string by injecting some JavaScript on each page. In the master page, I have: public partial class TheMasterPage : System.Web.UI.MasterPage { protected void Page_Init(object sender, EventArgs e) { if (Session[ ...

Exploring new possibilities in ChartJS with the use of multiple Y

I have successfully created a line chart using Chart.js with two datasets, each having its own Y scale and axis. The code for my datasets and options is as follows: datasets: [{ fill:false, label: 'Heat', yAxisID: "y-axis-1", da ...

Is it possible to incorporate two ng-repeat directives within a single td element in a table?

The results so far Expected outcome Please advise me on how to incorporate two ng-repeats within one td. When I use a span tag afterwards, the expected result is not achieved. I have used one ng-repeat in the td and the other in a span tag, which is why t ...

Issue encountered: ENOENT - There is no file or directory located at the specified path for ... .steampath

I am encountering an issue while attempting to launch the development server on a React project that has been dormant for quite some time. After executing npm install and npm start, I encountered the following error message. Despite my efforts to manua ...

Refreshing an array in Javascript

I'm utilizing ajax to retrieve data from a database and using the DOM to generate the HTML for a compact weather widget. Within this process, I have an Array of elements called _weather. While it populates correctly, I'm encountering difficulti ...

Is there a way to bring in both a variable and a type from a single file in Typescript?

I have some interfaces and an enum being exported in my implementation file. // types/user.ts export enum LoginStatus { Initial = 0, Authorized = 1, NotAuthorized = 2, } export interface UserState { name: string; loginStatus: LoginStatus; }; ex ...

Concealing or revealing an image with jQuery when hovering

I currently have 3 <a> tags within my html, each containing 2 images. Specifically, the greyscale images are the ones that are visible while the colored ones are set to display:none. I am aiming to achieve a functionality where upon hovering over th ...

Eliminating unnecessary symbols in asp.net with the help of Json

My goal was to eliminate unwanted html elements from my output, such as " , ', and more. Here is the code I used within my script tag: scope.categorywithouthtml = function () { return sce.trustAsHtml(scope.directories.dirurl); return ...

Table header sticking does not work when overflow is set to scroll or auto

After trying numerous solutions without success, I am reposting this question. My table has a horizontal scroll and I attempted to make the table header sticky using position:sticky, but it caused the scrolling functionality to stop working. Is there a wa ...

Having trouble retrieving the data from a post request in Express

I'm encountering an issue while attempting to access the data in a POST request. Even after using console.log(req.body), I only receive an empty {}. My suspicion is that the error may lie somewhere within the markup? Below is the relevant client-sid ...

What is the best way to add an element from a parent component to an array within a child component in a Vue 3 application?

I am in the process of transitioning from Vue's Options API to the Composition API, and as part of this transition, I have built a small Todo App. Within App.vue, my code looks like this: <template> <div id="app"> <div ...

What is the best way to prevent a fetch request from being initiated before the authentication token has been received

After successfully logging in, the data request fetch function needs to send the request with the saved token bearer. However, the data fetch is not waiting for the token and is receiving an Unauthorized access code. This is how my data request fetch func ...

Ways to display a GIF image as a pop-up during data loading in an MVC application

I am working on a project using the MVC framework. The application retrieves a large amount of data during loading. I would like to display a loading image - a .gif file while fetching records. Below is the code snippet I am currently using: //Loads rec ...