Search code examples
reactjsgraphqlapollo

Dynamically (server side) adding and removing columns in ag-grid with GraphQL(Apollo), React


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?


Solution

  • 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.