skip to Main Content

I have the following issue:

I am using GraphQL to query data from a huge table with many columns. The users want to be able to add/remove columns based on their preferences. I know that ag-grid offers adding/removing columns, but only client side (all columns are loaded). Because of the table size, this is not possible. I am trying to dynamically build a list of fields that I need, add them to a GraphQL query and run the query again. (again, because it runs once on page load.)

Here is an example of the query:

  query headers{
    getHeaders{
      headerId
      name
      description
      date
    }
  }

this is how I am currently doing the call:

const GET_HEADERS = gql`
    query headers {
        getHeaders {
            ${headerFields.join('n')}
        }
    }
`;

const { loading, error, data } = useQuery(GET_HEADERS);
setRowData(data.getHeaders);

headerFields gets updated, but how do I ask Apollo to take the new query string and execute it again?

I’ve seen few people saying that dynamic queues are not a good practice, but in this case I see no other solution. I’ve tried using refetch() but it doesn’t change the query fields. It basically updates the cache.

What are my options here?

2

Answers


  1. Chosen as BEST ANSWER

    The way I solved this is using directive: https://www.apollographql.com/docs/apollo-server/schema/directives/

    const GET_HEADERS = gql`
      query headers(
        $headerId: Boolean!
        $name: Boolean!
        $description: Boolean!
        $date: Boolean!
      ) {
        getHeaders {
          headerId @include(if: $headerId)
          name @include(if: $name)
          description @include(if: $description)
          date @include(if: $date)
        }
      }
    `;
    
    const { loading, error, data } = useQuery(GET_HEADERS, {
      variables: {
        headerId: false,
        name: true,
        description: false,
        date: true,
      },
    });
    

    now I can set the variables to true and false like this:

    const setAttributes = (attributes) => {
        if (Array.isArray(attributes)) {
            const updatedState = {};
            Object.keys(state).forEach((key) => {
                updatedState[key] = attributes.includes(key);
            });
            setState(updatedState);
        } else {
            console.error('Invalid attributes. Please provide an array.');
        }
    };
    

    Here is the neat part, when I setState, which basically updates my state hook which looks like this:

    state = {headerId: false,
            name: true,
            description: false,
            date: true}
    

    it automatically does another graphql request.


  2. The simplest way that comes to mind is to use components.

    1. ComponentA – has the controls that allow the user to pick which fields s/he wants, saving that list as state. This Component would build the query as a prop that it would use to call
    2. ComponentB – this would execute the query passed in via prop using useQuery and render the results.

    That way whenever the user changed the state of ComponentA by editing the field list, ComponentB would be forced to rerun the query and rerender.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search