What's the best way to switch between grid and list view in Vue.js?

    isGridView: true,
    isListView: true,

    methods: {
            
            switchView: function() {
                
          this.isGridView = !this.isGridView;
          
            },

            switchData: function () {

                this.isListView = !this.isListView;
            }
  <div class="product-grid1">item1</div>
     <div class="product-grid2">item2</div> 
     <div class="product-grid3">item3</div>
     
      <div class="product-list1">item1</div>
     <div class="product-list2">item2</div> 
     <div class="product-list3">item3</div>
     
      <div id="app-gridview">

            <div>
                <button class="button" v-on:click="switchView()"></button>
                <button class="button" v-on:click="switchData()"></button>
            </div>

            <div v-bind:class="[ isGridView ? 'grid-wrapper' : 'list-wrapper' ]">

                <div class="grid-row" v-if="isGridView">
                    <div class="grid-header" v-for="name in gridData.columns">{{ name }}</div>
                </div>

                <!-- GridView structure -->
                <div v-if="isGridView" class="grid-row" v-for="row in gridData.data">
                    <div class="list-row-item" v-for="name in gridData.columns">
                        <div>{{ row[name] }}</div>
                    </div>
                </div>

                <!-- ListView structure -->
                <div v-if="!isGridView" class="list-row" v-for="row in gridData.data">
                    <img v-bind:src="row.ImagePath" class="list-image" />
                    <div class="list-property">
                        <div class="list-row-item" v-for="name in gridData.columns">
                            <div class="list-property-name">{{ name }}</div>
                            <div>{{ row[name] }}</div>
                        </div>
                    </div>
                </div>

            </div>

I attempted to create functionality for toggling between list and grid views. I have initialized variables isGrid and isList as true, and used a ternary operator in Vue.js to enable switching between the two views.

Could you please assist me with implementing the toggle feature between list and grid views?

Answer №1

For those looking to create a component with a changeable view, I highly recommend utilizing the container-presentational component pattern. It's incredibly simple to manage and makes adding new "views" of data a breeze.

// Showing grid view
// Presentational component:
// Displays only what is passed through props
Vue.component("GridView", {
  props: ["users"],
  computed: {
    headers() {
      if (!this.users.length) return []
      return Object.keys(this.users[0])
    },
  },
  template: `
    <table>
      <thead>
        <tr>
          <th
            v-for="header in headers"
            :key="header"
          >
            {{ header }}
          </th>
        </tr>
      </thead>
      <tbody>
        <tr
          v-for="user in users"
          :key="user.id"
        >
          <td
            v-for="(val, key) in user"
            :key="user.id + '-' + key"
          >
            {{ val }}
          </td>
        </tr>
      </tbody>
    </table>
  `
})

// Displaying the list view
// Presentational component:
// Displays only what is passed through props
Vue.component("ListView", {
  props: ["users"],
  template: `
    <ol>
      <li
        v-for="user in users"
        :key="user.id"
      >
        <div
          v-for="(val, key) in user"
          :key="user.id + '-' + key"
        >
          {{ key }}: {{ val }}
        </div>
      </li>
    </ol>
  `
})

// Managing the data:
// Fetching, mapping, transforming, etc.
// Renderless component
Vue.component("DataContainer", {
  data() {
    return {
      users: []
    }
  },
  mounted() {
    this.fetchUsers()
  },
  methods: {
    async fetchUsers() {
      try {
        const response = await fetch('https://jsonplaceholder.typicode.com/users')
        const json = await response.json()
        this.users = json.map(({
          id,
          name,
          username,
          email
        }) => ({
          id,
          name,
          username,
          email
        }))
      } catch (err) {
        console.error(err)
      }
    }
  },
  render(h) {
    // Renders nothing, just provides the data
    // By passing it through "users"
    return this.$scopedSlots.default({
      users: this.users,
    })
  },
})

// The Vue instance
new Vue({
  el: "#app",
  data() {
    return {
      layout: "list-view",
    }
  },
  methods: {
    switchView() {
      this.layout = this.layout === "list-view" ? "grid-view" : "list-view"
    }
  },
  template: `
    <div>
      <button
        @click="switchView"
      >
        SWITCH VIEW
      </button>
      <data-container>
        <template
          #default="{ users }"
        >
          <component
            :is="layout"
            v-bind="{ users }"
          />
        </template>
      </data-container>
    </div>
  `,
})
table {
  border-collapse: collapse;
}

table,
tr,
th,
td {
  border: 1px solid black;
}

td,
th {
  padding: 4px 8px;
}

th {
  background-color: rgba(0, 0, 0, 0.3);
}
<script src="https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="5d2b28381d6f736b79767f">[email protected]</a>/dist/vue.js"></script>
<div id="app"></div>

If you're aiming for flexibility, extensibility, and maintainability in your design, consider implementing this setup instead of solely focusing on correcting specific v-if condition handling. This approach will provide a more robust solution in the long run.

Answer №2

This is the most efficient approach

<template>
  <button @click="toggleList">change display style</button>

  <component
    :is="currentComponent"
    :columns="gridData.columns"
    :items="gridData.data"
  />
</template>

<script>
import gridComponent from "./your-grid-component.vue";
import listComponent from "./your-list-component.vue";

export default {
  components: {
    gridComponent,
    listComponent,
  },
  data() {
    return {
      listType: "grid", //grid/list
      gridData: {
        columns: [],
        data: [],
      },
    };
  },
  methods: {
    toggleList() {
      this.listType = this.listType === "grid" ? "list" : "grid";
    },
  },
  computed: {
    currentComponent() {
      return this.listType === "grid" ? "gridComponent" : "listComponent";
    },
  },
};
</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

Suggestion for implementing numerous ajax countdown timers (one call per second)

I am currently developing a system with 100 countdown timers that each make an ajax call every second to retrieve the endTime from the database and update the countdown time. The reason for calling this every second is because the endTime can be altered. ...

Is there a way to determine whether all fields in a schema have been populated or remain empty?

I am working with a schema that looks like this: How can I determine if all the fields in the schema have been filled or not? The front-end (React.js) includes an onboarding process where users who are logging in for the first time need to complete onboa ...

Ensuring React Native/Redux child components receive the latest state updates with every change

When using <NavigationCardStack/> as the root component in React Native and Redux to render routes with _renderScene(), I noticed that the updated state is not always passed down every time there is a state change. Despite having console.log(this.pro ...

Assign the state to a new object by preserving matching values from the previous state

In my current state, I have an object structured like this: stateObject = {0: 400, 1: 500, 2: 600} Whenever my component rerenders on componentWillUpdate, an additional column is added carrying over the value at key index 0 (400). My goal is to update th ...

Is it possible to utilize React hooks within a conditional statement?

My current situation involves an object serving as a state, complete with various properties. Now, I am looking to update this state within a specific condition using a hook. However, this update seems to trigger an infinite loop. The question at hand is ...

What is the best way to transform parameters in axios requests into objects?

Within my ReactJs app, I have implemented the following code: axios .get(`/shipping/get-shipping-values`, { params: { products: [ { ...product, quantity, }, ], ...

The final value is always returned by jQuery's each method

Is there a way to prevent the .each() function from selecting the last value every time it runs? var items = ["item1", "item2", "item3"]; $("#list li").each(function() { var addedClass; if ($(this).hasClass("one")) { addedClass = "red"; } else ...

What could be causing my function to not register with my EventListener?

I'm attempting to perform an action when I click on an element. I have added an eventListener to change the value of a variable upon clicking on that element. However, the eventListener is not working as expected. When I debug the code, it seems like ...

Accessing child form data from parent component in VueJs

I have a form in my child component: <form @submit="submitForm"> <input type="text" v-model="textInput" /> </form> export default { name: "childComp", data: function() { return { textInput: "" } } } From the parent ...

Frontend utilizing the Next-auth Github Provider for Profile Consumption

After following the official documentation for implementing SSO with the Next-auth Github provider in my App, I encountered an issue where the Client API documentation suggested using useSession() to retrieve session information, but it was not returning t ...

Making Jquery functions work with Internet Explorer (including toggle and animate)

Why is this jQuery code snippet not functioning as expected in Internet Explorer? It works flawlessly across all Webkit browsers. $('#logo').toggle(function() { $('#about').animate({'top': '-400px'},'slow&a ...

JavaScript Array failing to transfer to PHP using AJAX

I've encountered a recurring issue with my code and despite searching for solutions, I can't seem to find one that works for me. The problem lies in trying to delete a specific row from a table based on whether the user selects a checkbox associa ...

sending data from an AngularJS application to an MVC controller in JSON format containing multiple arrays

Currently, I am working on a project that involves using AngularJS and MVC. I am transferring data from an AngularJS controller to my MVC controller using $http.post(). At the moment, I am using a single object or JSON array to retrieve data as follows: pu ...

Encountering an ongoing problem with trial repetition in JsPsych, which is causing the looping to continue endlessly without

As a beginner in JsPsych, I'm diving into creating a basic math quiz task to sharpen my skills. The goal is to generate random math questions as prompts and stop the task after 10 correct answers. I've managed to code that selects random math pro ...

Utilizing $templateCache with ui-router and minifying in AngularJS 1.x

Posting this as a question-answer post. How can one effectively utilize the $templateCache in the templateProvider of a route within ui-router when attempting to refactor the code? Injection is ineffective, and Angular cannot inject by reference. For ins ...

Which is more efficient in JavaScript: Arrays, Object literals, or JSON for achieving better performance?

I'm facing a tough decision in choosing the most effective option. Currently, I have a simple array set up like this: var array = [ '/index1.html', '/index2.html', '/index3.html' ]; While this array consists ...

Leveraging personalized AngularJS directives in conjunction with ExpressJS routing

I built my own AngularJS application following a tutorial at . However, I encountered an issue when trying to integrate it with an ExpressJS/Node backend. The tutorial only covers a single view with a single controller, while my Angular app includes multip ...

Utilize jQuery's animate method to scroll to the top after toggling a class in Vue

I am in the process of developing a FAQ page using vue.js Here is what I have implemented so far: <li v-for="i in items | searchFor searchString" v-on:click="toggleCollapse(i)" :class="{ collapsed: i.collapse, expanded: !i.collapse }" > <p> ...

Loading data into a secondary dropdown list depending on the choice made in the primary dropdown list using MVC2

I encountered a similar issue as detailed in this question and attempted to implement the suggested solution. However, I struggled to get it to work, likely due to my limited understanding of jquery and javascript. Upon inspecting it in Firebug, I noticed ...

A guide on arranging and styling last names in an array in alphabetical order using JavaScript!

I created an array called moonwalkers and developed a function named alphabetizer to organize the names in alphabetical order with the last name appearing first. Although it functions correctly, I am seeking ways to enhance the code. For my reference, I ...