vue.jsag-gridag-grid-vue

How to pass props to custom header component using ag-grid?


I'm using Vue 3 with ag-grid and want to setup a new ColDef like so

const colDef: ColDef = {
  field: 'objectKey',
  headerComponent: ColumnHeader, // my custom component
  headerComponentParams: {
    foo: 'bar'
  },
}

My ColumnHeader component defines its props for now

<script setup lang="ts">
const props = defineProps<{
  foo: string;
}>();
</script>

Running the app gives me the following error

[Vue warn]: Missing required prop: "foo" ...

This is because the whole props are undefined.


For reproduction purposes

Plunker snippet https://plnkr.co/edit/OoOD0I8W5NgYX45u which is based on https://www.ag-grid.com/vue-data-grid/component-header/#example-custom-header-component

You will get the error

Missing required prop: "name" ...


Based on https://github.com/ag-grid/ag-grid-vue-example/issues/14 it should work as expected I think. Does someone know what's wrong or missing?


Solution

  • your document clearly states 1. how to use headerComponent in columnDefs and 2. how parameters are passed down to custom header components.

    1. pass a component name as string, just like mounting an external component with <component />. It receives both component itself and mounted component's name in string. My guess is that AgGridVue also uses <component /> internally.
    // main.js
    data: function () {
        return {
          rowData: [
            {
              foo: 'bar',
            },
          ],
          columnDefs: [
            {
              field: 'foo',
              headerComponent: 'CustomHeader',
              headerComponentParams: {
                name: 'test',
              },
            },
          ],
        };
      },
    

    When a Vue component is instantiated the grid will make the grid APIs, a number of utility methods as well as the cell and row values available to you via this.params - the interface for what is provided is documented below.

    1. modify ColumnHeader to use this.params instead of props.
    // customHeaderVue.js
    export default {
      template: `
          <div>
            *{{ name }}*
          </div>
        `,
      computed: {
        name() {
          return this.params.name;
        },
      },
    };
    

    working demo: https://plnkr.co/edit/L7X6q3Mr7K0pewO8

    edit: ag-grid's IHeaderParams does not support generics. to extend given type without generics, please use these methods.

    import type { IHeaderParams } from "ag-grid-community";
    // fig 1
    // combine with type intersection
    type CustomHeaderParams = IHeaderParams & { name: string };
    
    // fig2
    // combine with interface extension
    interface CustomHeaderParams extends IHeaderParams {
      name: string;
    }
    

    here are typed examples of CustomHeader.vue

    // fig 1. Vue3 composition API, with <script setup>
    <script lang="ts" setup>
    import { defineProps, onMounted, ref } from "vue";
    import type { IHeaderParams } from "ag-grid-community";
    type CustomHeaderParams = IHeaderParams & { name: string };
    
    const props = defineProps<{ params: CustomHeaderParams }>();
    const name = ref(props.params.name);
    </script>
    
    <template>
      <div>*{{ name }}*</div>
    </template>
    
    // ------
    // 2. Vue3 options API, without <script setup>
    <script lang="ts">
    import { defineComponent, type PropType } from "vue";
    import type { IHeaderParams } from "ag-grid-community";
    type CustomHeaderParams = IHeaderParams & { name: string };
    export default defineComponent({
      props: {
        params: {
          type: Object as PropType<CustomHeaderParams>,
        },
      },
      setup(props) {
        return { name: props.params?.name ?? "" };
      },
    });
    </script>
    
    <template>
      <div>*{{ name }}*</div>
    </template>
    

    note: I've suggested using the component's name in columnDefs.headerComponent because the official document says so, and seems fine in the working demo; but it actually depends on the Vue API. I assume it has something to do with Vue internal variable scope.