Update individual component based on selected value

I am working on a blogs page that consists of two main components: filter and card

<template>
  <div>

    <div v-if='$apollo.loading'>Fetching data...</div>
    
    <div v-else>
      <FilterComponent :categories='categories' />

      <Card :blogs='blogs' />
    </div>

  </div>
</template>

<script>
import blogsGQL from '../graphql/blog/blog.graphql'
import categoriesGQL from '../graphql/category/category.graphql'
import Card from '~/components/Blog/Card'
import FilterComponent from '~/components/Blog/FilterComponent'

export default {
  name: 'Blogs',
  components: { FilterComponent, Card },
  layout: 'blog',

  apollo: {
    blogs: {
      query: blogsGQL,
      prefetch: true
    },
    categories: {
      query: categoriesGQL,
      prefetch: true
    }
  }
}
</script>

In the filterComponent, there is a select dropdown filled with categories from the database. When a category is selected, a GraphQL query is triggered to fetch blog posts filtered by category_id.

<template>
  <div class='w-full bg-gray-200 dark:bg-gray-900 py-10'>
    <div class='container mx-auto px-6 flex items-start justify-center'>

      <form id='filter' @submit.prevent>
        <div class='mt-16 flex flex-col  w-full'>
          <select id='category'
                  v-model.number='selected'
                  class='dark:border-gray-700 pl-3 py-3 shadow-sm rounded text-sm focus:outline-none focus:border-indigo-700 bg-transparent placeholder-gray-500 text-gray-500 dark:text-gray-400'
          >
            <option value='0' selected>Choose category</option>
            <option v-for='category in categories' :key='category.id' :value='category.id'>
              {{ category.category }}
            </option>
          </select>
        </div>
      </form>
    </div>
  </div>
</template>

<script>
import blogPostByCategoryId from '~/graphql/blog/blogByCategoryId.graphql'

export default {
  name: 'FilterComponent',

  props: {
    categories: {
      type: Array,
      required: true
    }
  },

  data() {
    return {
      selected: 0
    }
  },

  apollo: {
    blogPostByCategoryId: {
      query: blogPostByCategoryId,
      variables() {
        return {
          category_id: this.selected
        }
      },
      skip() {
        return !this.selected
      }
    }
  }
}
</script>

Now I need to update the card component with the new data received from the filter component. Is it possible to pass the blogPostByCategoryId result back into the card component?

EDIT:

I made some progress by creating an index.js file inside the store directory of Nuxt with the following code:

import blogsGQL from '~/graphql/blog/blog.graphql'

export const state = () => ({
  blogs: []
})


export const actions = {
  async nuxtServerInit({ commit }, context) {
    const client = context.app.apolloProvider.defaultClient

    const response = await client.query({ query: blogsGQL })

    commit('setBlogs', response.data.blogs)
  }
}

export const mutations = {
  setBlogs(state, blogs) {
    state.blogs.push(...blogs)
  },

  filter(state, categoryId) {
    return state.blogs.filter(blog => blog.category_id === categoryId)
  }
}

I retrieve blog posts from the GraphQL API and store them in the state. I pass this data down to the card component in my parent component like so:

      <Card :blogs='blogs' />


  computed: {
    blogs() {
      return this.$store.state.blogs
    }
  },

However, when trying to loop over the array inside the card component, all I get is blank space. The data is present in the blogs array when console logged.

EDIT 2:

I have updated my file and created a getter to filter the blogs:

export const getters = {
  filterdBlogs: state => (categoryId) => {
    return state.blogs.filter(blog => blog.category_id === categoryId)
  }
}

I call this method in the Apollo update method within the filterComponent:

      update(data) {
        const id = data.blogByCategoryId[0].category_id

        this.$store.getters.filterdBlogs(id)
      }

The filtering seems to work correctly, but the card component is not being updated with the filtered data.

EDIT 3:

To address the updating issue, I made changes to the card component by directly accessing the store:

// card component

<template>
  <div class='w-full bg-gray-200 dark:bg-gray-900 py-10'>
    <div class='container mx-auto px-6 flex justify-center'>
      <div class='w-full'>
        <div v-for='blog in blogs'
             :key='blog.id'
             class='flex flex-row  mx-auto bg-white dark:bg-gray-800 justify-center shadow rounded'>
          <div class='w-full lg:w-1/3 px-12 flex flex-col items-center py-10'>
            <div class='w-24 h-24 mb-3 p-2 rounded-full bg-gray-200 dark:bg-gray-700 flex items-center justify-center'>
              <img class='w-full h-full overflow-hidden object-cover rounded-full'
                   :src='`https://tuk-cdn.s3.amazonaws.com/assets/components/grid_cards/gc_${blog.id}.png`'
                   alt='avatar' />
            </div>
            <h2 class='text-gray-800 dark:text-gray-100 text-xl tracking-normal font-medium mb-1'>{{ blog.title }}</h2>
            <p class='text-gray-600 dark:text-gray-100 text-sm tracking-normal font-normal mb-8 text-center w-10/12'>
              {{ blog.big_text }}</p>
            <p class='text-gray-600 dark:text-gray-100 text-sm tracking-normal font-normal mb-8 text-center w-10/12'>
              {{ blog.small_text }}</p>
            <div class='flex items-start'>
              <div class='mx-6 border-l border-r'>
                <NuxtLink :to='`blog/${blog.slug}`'>
                  <button type='submit'
                          class='group relative w-full flex justify-center py-2 px-4 border border-transparent text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500'>
                    Read more
                  </button>
                </NuxtLink>
              </div>
              <div class='mx-4 border-l border-r'>
                <h2
                  class='group relative w-full flex justify-center py-2 px-4 border border-transparent text-sm font-medium rounded-md text-white text-black'>
                  Posted on {{ blog.created_at | formatDate }}
                </h2>
              </div>
              <div class='mx-4 border-l border-r'>
                <h2
                  class='group relative w-full flex justify-center py-2 px-4 border border-transparent text-sm font-medium rounded-md text-white text-black'>
                  Updated on {{ blog.updated_at | formatDate }}

                </h2>
              </div>
            </div>
          </div>
        </div>
        <!-- Card code block end -->
      </div>
    </div>
  </div>
</template>
<script>
export default {
  name: 'Card',

  filters: {
    formatDate: (dateStr) =>
      Intl.DateTimeFormat('us-EN').format(new Date(dateStr))
  },

  computed: {
    blogs() {
      return this.$store.state.blogs
    }
  }

}
</script>

When a value is selected in the dropdown menu, the state is not updated:

// dropdown component

<template>
  <div class='w-full bg-gray-200 dark:bg-gray-900 py-10'>
    <div class='container mx-auto px-6 flex items-start justify-center'>

      <form id='filter' @submit.prevent>
        <div class='mt-16 flex flex-col  w-full'>
          <select id='category'
                  v-model.number='selected'
                  class='dark:border-gray-700 pl-3 py-3 shadow-sm rounded text-sm focus:outline-none focus:border-indigo-700 bg-transparent placeholder-gray-500 text-gray-500 dark:text-gray-400'
          >
            <option value='0' selected>Choose category</option>
            <option v-for='category in categories' :key='category.id' :value='category.id'>
              {{ category.category }}
            </option>
          </select>
        </div>
      </form>
    </div>
  </div>
</template>

<script>
import blogPostByCategoryId from '~/graphql/blog/blogByCategoryId.graphql'

export default {
  name: 'FilterComponent',

  props: {
    categories: {
      type: Array,
      required: true
    }
  },

  data() {
    return {
      selected: 0
    }
  },

  apollo: {
    blogPostByCategoryId: {
      query: blogPostByCategoryId,
      variables() {
        return {
          category_id: this.selected
        }
      },
      skip() {
        return !this.selected
      },
      update(data) {
        const id = data.blogByCategoryId[0].category_id

        this.$store.commit('filter', {
          categoryId: id
        })
      }
    }
  }
}
</script>

<style scoped>

</style>

The filter method in Vuex mutations looks like this :

export const mutations = {
  filter(state, payload) {
    return state.blogs.filter(blog => blog.category_id === payload.categoryId)
  }
}

Answer №1

When updating Vuex state, ensure you are handling mutations correctly. The proper format for mutations is:

export const state = () => ({
     blogs: [],
     search: null // If you require multiselect, use an array [] with IDs
})

export const getters = {
  filterBlog(state, payload) {
    return state.search ? state.blogs.filter(blog => +blog.category_id === +state.search) : state.blogs
  }
}

export const mutations = {
  setBlogs(state, blogs) {
    state.blogs.push(blogs)
  },
  search(state, id) {
     state.search = id
  }
}

Card component:

<div v-for='blog in blogs'>

computed: {
blogs() {
return this.$store.getters.filterBlog
}
}

Dropdown component:

update(data) {
const id = data.blogByCategoryId[0].category_id

this.$store.commit('search', id)
}

Remember, when working with Vuex, make sure to update the current state directly instead of returning a new one as done in Redux Reducer.

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

The jQuery toggle function is malfunctioning when applied to the rows of a table

I have been experimenting with toggling table rows using jquery. Initially, the state is hidden This feature is functioning properly $('.table tr.items.' + name).each(function() { $(this).show(); }); Furthermore, this snippet of code is wor ...

What is the best way to recycle a component instance in Nuxt.js?

Recently, I developed a cutting-edge single-page application using Nuxt.js 2 and Vue2. The highlight of this app is a complex WebGL visualizer showcasing a 3D scene across two distinct sections: SectionDesign and SectionConfirm <template> <Sec ...

Top method for centering a flexible SVG vertically once the page width becomes too narrow

Currently, I have two SVG images displayed side by side on a webpage. One SVG needs to maintain a fixed size while the other should scale as needed, and I have achieved this functionality. However, I am facing an issue where I want the two SVGs to align v ...

"Need help passing an API key in the header of a Vue.js project? I recently encountered this issue while using a

How can I include an API key in the header of a Vue.js request? I am using DRF pagination. methods: { getPostData() { axios .get("http://192.168.43.126:8000/api/?page=" + this.currentPage, { headers: { &q ...

Unveiling the Magic: Enhancing Raphaeljs with Interactive Click Events on a Delicious Slice of the

I'm having trouble responding to a click event on each slice of a Raphael Pie Chart. I've tried implementing the code below, but it doesn't seem to be working. The code is just two lines, commented as "My Code", in the example from the offic ...

Updating an HTML Table with AJAX Technology

I'm struggling to figure out how to refresh an HTML table using AJAX. Since I'm not the website developer, I don't have access to the server-side information. I've been unable to find a way to reload the table on this specific page: I ...

Strategies for sending checkbox data to MySQL via AJAX and jQuery

Looking for assistance on passing values of multiple checkboxes to MySQL using arrays with AJAX (jQuery). I've written two separate code snippets, is there someone who can help me merge them? $(document).ready(function(){ var selected = []; $(&apo ...

The @output decorator in Angular5 enables communication between child and

Hello fellow learners, I am currently diving into the world of Angular and recently stumbled upon the @output decorators in angular. Despite my best efforts to research the topic, I find myself struggling to fully grasp this concept. Here's a snippet ...

Guide on displaying the value of an element in a Vue modal

I am working with a list of items displayed as <li> elements in a loop. When one of these elements is clicked, I would like a modal box to open up displaying specific content related to that particular element. The following data represents the item ...

Exploring the Contrast between window.location.href and top.location.href

I'm curious about the distinction between window.location.href and top.location.href. Can anyone explain this to me? Furthermore, I'd like to know when it's appropriate to use each one. Which option is more suitable for redirection after a ...

A "Uncaught TypeError" error occurs when trying to execute a function using the dollar sign

After successfully recognizing the hover function, the console displays an error message: Uncaught TypeError: $ is not a function <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script> <script> $(docume ...

"Automate the process of manual content duplication with JavaScript's for each replacement

Seeking a solution to automate the selection process without writing individual JS scripts for every input. For instance, having 10 double inputs (total of 20 inputs) and utilizing the each() function or other methods by only declaring selectors. Find th ...

Solving an object in ui-router state using ui-sref

Dealing with a large JSON object in an Angular controller and wanting to pass it to the controller of a template that will be displayed in a ui-view. I am aware that parameters can be passed to states using ui-sref, but I do not want this object to be visi ...

Transmitting data from express server to vue.js interface

Hey there, I am facing a bit of a complex situation and could really use some help. Here's what I've got: an application split into server-side using node/express and client-side with Vuejs. The issue arises when I try to create a user on the ba ...

Visual Studio Code encounters a Node.js error stating "Module not found"

I have been struggling to run my Node.js program in VSCode. Despite trying various solutions found on StackOverflow, none of them seem to be working for me. I even attempted the Json file method, but unfortunately, that didn't work either. internal/mo ...

The functionality of the "Slots" prop has no impact when used on the material-ui Slider component

Trying to understand the purpose of the "slots" prop in relation to customizing how inner components like track and thumb are rendered within the Slider component. A basic example of rendering a Slider component is shown below const marks = [ { value: 0 ...

Verifying a checkbox selection within an Autocomplete feature using MUI

[ { label: 'First', checked: false }, { label: 'Second', checked: true } ] Here is a brief example of how the data may be structured. I am utilizing Material UI's Autocomplete feature to enable searching based on labels. Thes ...

Step-by-step guide for sending data using module.exports in a node.js application

Currently, I am working on implementing a feature that will allow users to input data and store it in a database collection. The technologies I am using for this project are Node.js, MongoDB, Mongoose, Express.js, and AJAX. My goal is to capture user inpu ...

What is the proper way to implement a $scope.$watch for a two-dimensional array in AngularJS?

Having trouble implementing an Angular watch on a multidimensional array I've got a screen where users can see two teams (outer array) with team sheets (inner array) for each team. They can drag and drop players to change the batting order. The batt ...

Error: myFunction has not been declared

Can anyone figure out what's going on here? http://jsfiddle.net/sVT54/ <button onclick="myFunction()">Click me</button> <p id="demo"></p> function myFunction() { document.getElementById("demo").innerHTML="Hello World"; } ...