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

What causes a 400 Bad Request error when attempting to send data using jQuery Ajax within the Spring framework

I am facing an issue with submitting JSON data through jQuery AJAX. I have searched for similar problems online, but none of the solutions seem to be working for me. $.ajax({ type : "POST", contentType : "applic ...

Encountering a 404 error when using Vue history mode in conjunction with an Express

I'm facing an issue with my Vue SPA hosted on an Express server. Whenever I use history mode and refresh the page, I encounter a 404 not found exception. I attempted to solve this problem by utilizing the connect-history-api-fallback package but unfor ...

Unable to utilize material tabs in this situation

Discovering the material tabs feature at https://material.angular.io/components/tabs/api#MatTab got me excited to implement it in my project. After adding the suggested import, I encountered an issue where I couldn't find the module "@angular/materia ...

How to include an href in a button using Pug without disrupting a form

Is there a way to create a button that redirects to my /leaderboard page once my quiz app submits? h1 Play Time 4 Trivia! button Go form(method='POST') ul each val in questions li ...

What are some effective methods for troubleshooting unidentified JavaScript functions within Chrome's performance analyzer?

Currently, I am utilizing Angular 4 and incorporating numerous anonymous arrow functions (() => {}). I am curious if it is feasible to identify these functions in Chrome's performance analyzer without assigning them names. Below is an example of t ...

Instructions on establishing a connection with a MongoDB server using JavaScript

Hello all, I am a complete beginner when it comes to working with mongodb and java script. I am currently trying to figure out how to establish a connection to my local mongodb instance using java script so I can retrieve a list of documents. Does anyone ...

displaying li tag depending on the index value within angularjs

I have an HTML structure similar to the following: <div class="main"> <ul> <li ng-repeat='save in saves'> <h3>{{save.name}}</h3> <div > <ul> ...

Working with Variables in JavaScript and PHP Scripting Languages

I have a PHP script that displays all the folders (categories) on my website: echo "<ul>"; foreach(glob('category/*', GLOB_ONLYDIR) as $dir) { $dir = str_replace('category/', '', $dir); echo '& ...

Client-sessions in ExpressJS fail to persist session data

I recently integrated the client-sessions module into my Express backend. After setting it up as follows: var sessions = require('client-sessions'); app.use(sessions({ cookieName: Constants.CLIENT_SESSION_NAME, // pi_client_session ...

Encountered a syntax hiccup in my PHP and JavaScript codes

Below is my PHP code snippet: echo ("<td><img src='edit.jpg' width='20' alt='Edit' title='EDIT DATA' onClick=\"swipe2('" + . mysql_result($result, $i, 'no'). + '');'style= ...

Eliminate nested object properties using an attribute in JavaScript

I am working with a nested object structured like this const data = [ { id: '1', description: 'desc 1', data : [ { id: '5', description: 'desc', number :1 }, { id: '4', description: 'descip& ...

Utilizing Vuex, is it possible to filter an array by incorporating another array in a Javascript view?

When using VueX, I am attempting to filter my "ListJobs" array based on the currentTag. Essentially, I want to return elements that match any of the values in the currentTag array with the rows role, level, languages, and tools. state: [ listJobs: ...

Having trouble with your custom AngularJS directive not functioning correctly?

I am facing an issue with my custom directive implementation. I have a custom directive that contains a table which references a controller. The ProjectController part works fine when it is not included in the code, but as soon as I put everything into the ...

Tracking user sessions using cookies, not relying on JavaScript like Google does

Currently, I am working in an environment that utilizes PHP on the server side and Javascript on the client side. In order to monitor user sessions, I regularly send a JS PUT request to the server every 5 seconds. This allows me to gather data such as the ...

Is it possible to reuse a variable within a single HTML tag when using Angular 2?

I encountered a strange issue with Angular 2 that may be a bug. I noticed that I couldn't print the same variable in a template twice within the same HTML tag. When I tried to use the following code, it resulted in error messages. <div class=" ...

Python sends back a list containing garbled characters to Ajax

Need help fixing the output of a Python list returned to Ajax, as it appears strange. ap.py @app.route('/_get_comUpdate/', methods=['POST']) def _get_comUpdate(): comNr = request.form.get('comNr') com_result ...

Is there a way to determine the actual time or percentage completion of a file upload using Telerik RadUpload?

Utilizing the Telerik upload file control with manager is a key component of my project: <telerik:RadUpload ID="RadUpload" Runat="server" MaxFileInputsCount="5" /> <telerik:RadProgressManager ID="RadProgressManager" Runat="server" /> For clie ...

Error message encountered in Rails Webpacker: "Uncaught TypeError: $(...).tooltip is not recognized as a function

I am working on a Rails 6 application where I compile assets using Webpack 4.39.1 with the help of the Webpacker gem. In my webpack configuration file (config/webpack/environment.js), I have included JQuery 3.4.1 and Popper.js as part of the ProvidePlugin ...

Implement a button transformation upon successful completion of a MySQLi update using AJAX

When displaying multiple database results with buttons that can be turned on or off inside a div, I am looking to implement AJAX to toggle the button state between ON and OFF upon clicking, and then update the button without refreshing or reloading the ent ...

Repurposing React key usage

section, I am curious to know if it is standard practice to reuse a React key from one component to another. For instance, in the Row component, the key obtained from the Column component is reused for mapping the children of Row. const Table = props =& ...