What is the best way to create a dynamic information page using both V-for and V-if in Vue.js?

Hey everyone, I recently attempted to set up this layout:

https://i.sstatic.net/WbcBX.png

This company offers a variety of services grouped into different categories, each containing sub-options and specific details.

This is how my JSON data is structured:

    {
        "services": [{
                "name": "COVID-19",
                "options": [
                    "COVID-19 Temperature Screening System"
                ],
                "information": {
                    "images": [
                        "http://placekitten.com/300/300"
                    ],
                    "description": "Lorem ipsum dolor sit amet consectetur, adipisicing elit. Qui, in."
                }
            },
            {
                "name": "Home",
                "options": [
                    "Camera",
                    "Fire Alarm",
                    "Motion Sensor"
                ],
                "information": {
                    "images": [
                        "http://placekitten.com/300/300"
                    ],
                    "description": "Lorem ipsum dolor sit amet consectetur, adipisicing elit. Qui, in."
                }
            },
....

The main issue I'm facing is figuring out how to utilize a v-if statement alongside a v-for loop to dynamically change the displayed product based on user selection. I encountered this error message:

26:11 error The 'this.JSON' expression inside 'v-for' directive should be replaced with a computed property that returns filtered array instead. You should not mix 'v-for' with 'v-if'

Could anyone provide guidance on using a computed property for this purpose as I am uncertain about its meaning? Here's the snippet related to the services page:

<template>
  <div class="services">
    <div class="header services__header">
      <h1 :class="$mq">Services</h1>
    </div>
    <div class="services__services-container">
      <div class="services__services-container__category-selection">
        <!-- GENERATE CATEGORIES -->
        <div
          class="services__services-container__category-selection__category"
          v-for="(item, index) in this.JSON"
          :key="`category-${index}`"
          :class="$mq"
        >
          <input type="radio" :name="item.name" :value="item.name" v-model="currentCategory" />
          <label :for="item.name">{{item.name}}</label>
        </div>
      </div>
      <!-- GENERATE SERVICES -->
      <div class="services__services-container__service-selection">
        <div
          class="services__services-container__service-selection__service"
          v-for="(item, index) in this.JSON"
          :key="`service-${index}`"
          :class="$mq"
          v-if="currentCategory === item.name"
        >
        <!-- ^^^ THIS V-IF IS NOT ALLOWED -->
          <div
            class="services__services-container__service-selection__service__wrapper"
            v-for="(option, index) in item.options"
            :key="`option-${index}`"
            :class="$mq"
          >
            <input type="radio" :name="option" :value="option" v-model="currentService" />
            <label :for="option">{{option.optionName}}</label>
          </div>
        </div>
      </div>
      <!-- GENERATE DESCRIPTIONS -->
      <div class="services__services-container__product-description">
        <div
          class="services__services-container__product-description__description"
          v-for="(item, index) in this.JSON"
          :key="`service-${index}`"
          :class="$mq"
        >
          <div v-for="(option, index) in item.options" :key="`option-${index}`" :class="$mq">
            <img :src="option.images" alt />
            <p>{{option.description}}</p>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import services from "@/JSON/services.json";
export default {
  name: "Services",
  data: function() {
    return {
      JSON: [],
      currentCategory: "Home",
      currentService: ""
    };
  },
  created: function() {
    //TO TEST
    this.JSON = services.services;
    this.JSON.forEach(element => {
      console.log(element);
    });
  }
};
</script>

<style lang="scss">
@import "@/scss/variables.scss";
@import "@/scss/button.scss";
@import "@/scss/header.scss";
@import "@/scss/input.scss";
.services {
  width: 100%;
  height: auto;
  display: grid;
  grid-template-rows: 15vh auto auto auto;

  &__services-container {
    padding: 2rem;
    & input {
      margin-right: 0.5rem;
    }

    &__category-selection {
      background-color: $colour-green;
      padding: 1rem;
      margin-bottom: 1rem;
    }

    &__service-selection {
      padding: 1rem;
      margin-bottom: 1rem;
      &__service {
        background-color: $colour-blue;
        margin-bottom: 1rem;
      }
    }

    &__product-description {
      background-color: $new-service;
      display: flex;
      justify-content: center;
      align-items: center;
      flex-direction: column;
      &__description {
        & img {
          margin-bottom: 1rem;
        }
        background-color: pink;
        display: flex;
        justify-content: center;
        align-items: center;
        flex-direction: column;
        text-align: center;
      }
    }
  }
}
</style>

Script portion:

<script>
import services from "@/JSON/services.json";
export default {
  name: "Services",
  data: function() {
    return {
      JSON: [],
      currentCategory: "Home",
      currentService: ""
    };
  },
  created: function() {
    //TO TEST
    this.JSON = services.services;
    this.JSON.forEach(element => {
      console.log(element);
    });
  }
};
</script>

Answer №1

If I were to suggest a different approach, it would be to implement the radio selection within the item itself as shown below:

  <div class="services">
    <div class="header services__header">
      {{currentCategory}}
      <h1 :class="$mq">Services</h1>
    </div>
    <div class="services__services-container">
      <div class="services__services-container__category-selection">
        <!-- GENERATE CATEGORIES -->
        <div class="services__services-container__category-selection__category" v-for="(item, index) in services" :key="`category-${index}`" :class="$mq">
          <input type="radio" :name="item.name" :value="item" v-model="currentCategory" />
          <label :for="item.name">{{item.name}}</label>
        </div>
      </div>

      <!-- GENERATE SERVICES -->
      <div class="services__services-container__service-selection" v-if="currentCategory!=null">
        <div class="services__services-container__service-selection__service" :class="$mq">
          <!-- ^^^ THIS V-IF IS NOT ALLOWED -->
          <div class="services__services-container__service-selection__service__wrapper" v-for="(option, index) in currentCategory.options" :key="`option-${index}`" :class="$mq">
            {{option}}
            <input type="radio" :name="option" :value="option" v-model="currentService" />
            <label :for="option">{{option.optionName}}</label>
          </div>
        </div>
      </div>

      <!-- GENERATE DESCRIPTIONS -->
      {{currentService}}
      <div class="services__services-container__product-description" v-if="currentService!=null">
        <div class="services__services-container__product-description__description" :class="$mq">
          <div :class="$mq">
            <img :src="currentCategory.information.images" alt />
            <p>{{currentCategory.information.description}}</p>
          </div>
        </div>
      </div>
    </div>
  </div>

Answer №2

26:11 error The 'this.JSON' expression inside 'v-for' directive should be replaced with a computed property that returns filtered array instead. You should not mix 'v-for' with 'v-if'

The essence of this error message is to utilize your v-if statement (which functions as a filter for the services) within a computed property, rather than directly in the template.

Instead of:

<template>
  <div
          class="services__services-container__service-selection__service"
          v-for="(item, index) in this.JSON"
          :key="`service-${index}`"
          :class="$mq"
          v-if="currentCategory === item.name"
        >
</template>

Consider using:

<template>
  <div
          class="services__services-container__service-selection__service"
          v-for="(item, index) in filteredJson"
          :key="`service-${index}`"
          :class="$mq"
        >
</template>

To do this, create a computed property named "filteredJson" in your script:

<script>
import services from "@/JSON/services.json";
export default {
  name: "Services",
  data: function() {
    return {
      JSON: [],
      currentCategory: "",
      currentService: ""
    };
  },
  created: function() {
    //TO TEST
    this.JSON = services.services;
    this.JSON.forEach(element => {
      console.log(element);
    });
  },
  computed: {
    filteredJson() {
      return this.JSON.filter(item=> currentCategory === item.name);
    }
  }
};
</script>

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

"Secure access with Keycloak authentication in a .NET Core API and Vue.js Single Page Application

Currently, I am utilizing .NET Core for the backend REST API and Vue.js for the frontend. In my current setup, I have implemented authentication through a cookie. However, I am now looking to switch to authenticating via Keycloak. The goal is to have the ...

Check out the new Bootstrap 5 form when it's successfully validated

I need to execute some JavaScript if my form is valid. I am using Bootstrap 5 and found this code, but I am unsure how to add 'if form.is_valid {}' <script> (function () { 'use strict' const forms = document.querySelectorAll(&apos ...

When Vue detects a change in declared parameters from an empty string, it automatically sends a

Within my application, I am making a request to the backend app and receiving a response with an ID such as { 'id': '12345'}. This ID is then saved as loadId within the data object: export default { name: 'SyncProducts', d ...

Understanding flow control is crucial in programming. When an if statement is used in a loop,

Unable to proceed past the initial if statement within the code snippet, even when intentionally setting it to false: while not scraped: print("sleep....") time.sleep(1) try: res = requests.get(url).content soup = BeautifulSoup ...

Sort by value or locate in a set without using the IN function

Currently, I am working on developing a MySQL query to enhance the functionality of a search feature. My goal is to customize the order of the results based on a specific array of ID's. After some experimentation, I managed to achieve this using a My ...

Include a personalized header in $http

In my factory, I have multiple functions that follow this structure: doFunction: function () { return $http({ method: 'POST', url: 'https://localhost:8000/test', data: {}, headers: { "My_Header" ...

Unraveling JSON using Java

I've been attempting to work with JSON data using Java, and I came across a library that seems promising: http://code.google.com/p/json-simple/wiki/DecodingExamples After adding the .jar file to my eclipse project's build path, which placed the ...

Tips for sending a request from a Nuxt.js client through a Nuxt.js server and successfully receiving the response on the client side

I am currently working on a Vue.js application that operates solely on the frontend with no server involved. The app sends multiple requests to various APIs, resulting in its complexity increasing over time. Unfortunately, some of these APIs pose problems ...

Steps to convert a PHP array to a JSON array instead of a JSON object using json_encode

I have an array written in PHP that looks like this: Array ( [0] => Array ( [id] => 0 [name] => name1 [short_name] => n1 ) [2] => Array ( [id] => 2 ...

Content moves as you scroll, not within a lightbox

I have implemented lightbox style overlays for my 'Read More' content on my website. However, I am facing an issue where the content within the lightbox does not scroll; instead, the background page scrolls. Any assistance with resolving this p ...

What is the method for creating a line break in text?

Here is some example code I have: <h3 class="ms-standardheader"> <nobr> Reasons for proposals selected and not selected </nobr> </h3> Now I also have an image to show. The problem is that my text appears too large, so I a ...

Using Logstash to import nested JSON data into Elasticsearch

I am facing a challenge with inserting a large amount (~40000) of nested JSON objects into an Elasticsearch index. The structure of the JSON objects is as follows: { "customerid": "10932" "date": "16.08.2006", "bez": "xyz", "birthdate ...

Angular 2 - Error: Regular expression missing forward slash syntax

Recently, I began working on an Angular 2 tutorial app using this repository. While I can successfully launch the app and display static content, I am facing challenges with rendering dynamic content from the component. I have a feeling that the error migh ...

Dragging the world map in D3 causes it to appear jumpy and erratic

I'm currently working on a Vue project to create an interactive world map that allows users to drag and zoom. I've attempted to integrate D3 for this purpose, but encountered an issue where the map jumps to the bottom right of the page whenever I ...

Create eye-catching banners, images, iframes, and more!

I am the owner of a PHP MySQL website and I'm looking to offer users banners and images that they can display on their own websites or forums. Similar to Facebook's feature, I want to allow users to use dynamic banners with links. This means the ...

Challenge with Angular *ngFor: Struggling to Access Previous Elements

In my angular and node application, I am using socket.io. When a user joins the room, they can see their username in the user list. If another user joins, the first user can see both usernames but the new user can only see their own. This pattern continues ...

How to set cells to plain text in google sheets

I've been grappling with a formatting issue that I'm hoping someone can assist me with. In my script, there's a point where I need to combine the date value (e.g., 11/20/2020) from one column with the time (3:00 PM) from another column. This ...

The function 'read_json' in Pandas is not functioning properly as anticipated

Having trouble loading a JSON file with pandas as expected! I've checked various Stack Overflow answers but my issue doesn't seem to be there. The structure of the JSON file is shown below: View JSON File Code snippet used to load the file:- im ...

React function causing website to freeze upon dispatch

I created a function in the child component to handle checkbox selection and trigger setDispatch(true). Unfortunately, whenever I check the checkbox, the website freezes and stops responding until I close and reopen it. Here is the function: const [ ...

Instead of using <div>, try substituting it with a different HTML page

Seeking assistance on an HTML page project that involves jQuery, CSS, and HTML without server-side integration. Encountering an issue when attempting to replace a <div> with content from another HTML file saved on my computer. The main page code sni ...