Grid's header click

Hi

How can I catch the event when a user clicked on a header cell and know what header was it in order to do something with it?

Thanks


11 Replies

MS Manivel Sellamuthu Syncfusion Team May 15, 2020 06:11 AM UTC

Hi Amos, 

Greetings from Syncfusion support. 

You can use actionBegin event of the Grid to achieve your requirement. To catch the event only while clicking the header Cell we can differentiate from other actions by requestType as sorting. Please refer the below code example and sample for more information. 

<template> 
  <div id="app"> 
    <div> 
      <ejs-grid ref="grid" id="grid" :dataSource="data" :allowSorting=true :actionBegin="actionBegin"> 
        <e-columns> 
          <e-column 
            field="OrderID" 
            headerText="Order ID" 
            textAlign="Right" 
            :isPrimaryKey="true" 
            width="100" 
          ></e-column> 
          <e-column field="CustomerID" headerText="Customer ID" width="120"></e-column> 
          <e-column field="Freight" headerText="Freight" textAlign="Right" width="120" format="C2"></e-column> 
        </e-columns> 
      </ejs-grid> 
    </div> 
  </div> 
</template> 
<script> 
import Vue from "vue"; 
import { GridPluginPageSort } from "@syncfusion/ej2-vue-grids"; 
import { ButtonPlugin } from "@syncfusion/ej2-vue-buttons"; 
import {gridData} from './data' 
Vue.use(ButtonPlugin); 
Vue.use(GridPlugin); 
export default { 
  data() { 
    return { 
      data: gridData 
    }; 
  }, 
  methods: { 
    actionBegin: function(args) { 
      if (args.requestType === "sorting") { 
      console.log(args); 
      // here we can catch the event while clicking the headercell 
      alert(args.columnName + ':' + args.direction); 
      } 
    } 
  }, 
 
  provide: { 
    grid: [PageSort] 
  } 
}; 
</script> 
 




Please let us know, if you need further assistance. 

Regards, 
Manivel 



AM Amos May 15, 2020 06:29 AM UTC

Thanks, actually I disabled sorting for all columns except one that requires sorting.
I guess I can use args.columnName to differentiate the column that does sorting to the rest that doesn't.
I will try your suggestion but if after my additional explanation there's another method to achieve what I wrote, please let me know.
Thanks


AM Amos May 15, 2020 08:29 AM UTC

As expected, I had to allow sorting again to all columns and implement your actionBegin method and distinguish the only column that needed sorting.
The problem is that sometimes the sorting + icon occurs before my intended code (router to another page).


MS Manivel Sellamuthu Syncfusion Team May 18, 2020 10:42 AM UTC

Hi Amos, 

Thanks for your update. 

By default the Sorted data will be applied to the Grid after the dataBound event of the Grid. So please explain more about your requirement with the Grid code. 

Please share the video demonstration or screenshot of the issue, to validate the issue on our end. If possible, you can try to replicate the issue in our given sample and revert us. 


Regards, 
Manivel 



AM Amos May 18, 2020 11:08 AM UTC

Please see here:

The first column should be sortable and it is, see the arrow.
The rest of the columns should be "clickable" and when clicked, I want it to route to another page.

Both are working with the following code
        <ejs-grid
          :dataSource="matrixData"
          :actionBegin="headerClicked"
          gridLines="Both"
          :allowSorting="true"
        >

        headerClicked: function(args) {
            if (args.requestType == "sorting" && args.columnName != undefined && args.columnName != "column1") {
                this.$store.dispatch("userData/updateMonth", { month: monthValue });
                this.$router.push("/monthlyView");
            }
        },

The problem is, as you wrote, is that sorting also happens right before the routing, this is not my intention.
If I disable sorting for those columns, assuming only my routing will happen, then headerClicked event is not triggered.
I was hoping that there is a way to get a headerClicked event even when the column is allowSorting = false;



MS Manivel Sellamuthu Syncfusion Team May 19, 2020 02:00 PM UTC

Hi Amos, 

Thanks for your update. 

From your explanation we can clearly understand your requirement. You can use headerTemplate for this requirement. 

The first column should be sortable and it is, see the arrow. 
The rest of the columns should be "clickable" and when clicked, I want it to route to another page. 
 
From the below code example you can see that sorting has been enabled for first column and disabled for the second column. Also as per your requirement we have used headerTempalte, so the sorting disabled column will be clickable.  

Please refer the below code example, sample and demo for more information. 

<template> 
  <div id="app"> 
    <ejs-grid ref="grid" :dataSource="data" :allowSorting="true" :allowPaging="true" height="273px"> 
      <e-columns> 
        <e-column field="no" headerText="Sort column" textAlign="Right" width="100"></e-column> 
        <e-column 
          field="name" 
          :headerTemplate="cTemplate" 
          :allowSorting="false" 
          headerText="Name" 
          width="120" 
        ></e-column> 
      </e-columns> 
    </ejs-grid> 
  </div> 
</template> 
<script> 
import Vue from "vue"; 
import { 
  GridPlugin, 
  Page, 
  Filter, 
  Sort, 
  Toolbar, 
  Edit 
from "@syncfusion/ej2-vue-grids"; 
import { data } from "./datasource.js"; 
 
Vue.use(GridPlugin); 
 
export default { 
  data() { 
    return { 
      data: [ 
        { no: 1, name: "Value1" }, 
        { no: 2, name: "Value2" }, 
        { no: 3, name: "Value3" } 
      ], 
      cTemplatefunction() { 
        return { 
          template: Vue.component("columnTemplate", { 
            template: `<div v-on:click="headerclicked($event,data)" class="headertemplate" style="color:red"> 
                    Field No 
                </div>`, 
            data: function() { 
              return { 
                data: {} 
              }; 
            }, 
            computed: {}, 
            methods: { 
              headerclickedfunction(e, data) { 
                console.log(e, data); 
// here you can perform your actions 
                alert(data.field+ " " + "Clicked"); 
              } 
            } 
          }) 
        }; 
      } 
    }; 
  }, 
  provide: { 
    grid: [PageFilterSortEditToolbar] 
  } 
}; 
</script> 
<style> 
@import "https://cdn.syncfusion.com/ej2/material.css"; 
</style> 



Please let us know, if you need further assistance. 

Regards, 
Manivel 



AM Amos May 20, 2020 02:01 PM UTC

Thanks,

Started to implement it but 2 questions

1. How can I show the original headerText of the column in the template (instead of field no)? I have 14 columns that needs this behavior so I will assign the same template but I want the relevant headerText to show/

2. In the headerClicked event, I need to update my store and to route somewhere else
this.$store.dispatch("userData/updateMonth", { month: monthValue });
this.$router.push("/monthlyView");
The problem: this in this context is not the root so I have no access to my $store and $router, both are undefined. How can I have access
to the outer this so I can have access to both?

Thanks


MS Manivel Sellamuthu Syncfusion Team May 21, 2020 01:04 PM UTC

Hi Amos, 

Thanks for your update. 

  1. How can I show the original headerText of the column in the template (instead of field no)? I have 14 columns that needs this behavior so I will assign the same template but I want the relevant headerText to show/
 
You can show the headerText of the corresponding column as like the below code example inside the headerTemplate. By default headerTemplate will corresponding column details inside the data property. 
 
   cTemplate: function() { 
        return { 
          template: Vue.component("columnTemplate", { 
            template: `<div v-on:click="headerclicked($event,data).bind(this)"  style="color:red" class="headertemplate"> 
// here we can show the headertext                  
 {{data.headerText}} 
                </div>`, 
            data: function() { 
              return { 
                data: {} 
              }; 
            }, 
 
 
2) The problem: this in this context is not the root so I have no access to my $store and $router, both are undefined. How can I have access 
to the outer this so I can have access to both? 
 
We suggest to use Vue Global Event Bus concept to achieve this requirement. By default this EventBus allows us to emit an event from one component and listen for that event in another component. So we can easily communicate with two Vue components by using this EventBus concept. 
 
Please refer the below code example and sample for more information. 
<template> 
  <div id="app"> 
    <ejs-grid 
      ref="grid" 
      :destroyed="destroyed" 
      :load="load" 
      :dataSource="data" 
      :allowSorting="true" 
      :allowPaging="true" 
    > 
      <e-columns> 
        <e-column field="OrderID" headerText="Order ID" width="120" textAlign="Right"></e-column> 
        <e-column 
          field="CustomerID" 
          :headerTemplate="cTemplate" 
          :allowSorting="false" 
          headerText="Customer Name" 
          width="150" 
        ></e-column> 
        <e-column 
          field="OrderDate" 
          :headerTemplate="cTemplate" 
          :allowSorting="false" 
          headerText="Order Date" 
          width="130" 
          format="yMd" 
          textAlign="Right" 
        ></e-column> 
 . . . 
        ></e-column> 
      </e-columns> 
    </ejs-grid> 
  </div> 
</template> 
<script> 
import Vue from "vue"; 
import { 
  GridPlugin, 
  Page, 
  Filter, 
  Sort, 
  Toolbar, 
  Edit 
from "@syncfusion/ej2-vue-grids"; 
 
Vue.use(GridPlugin); 
 
//initialize the eventhub 
Vue.prototype.$eventHub = new Vue(); 
 
export default { 
  data() { 
    return { 
      data: [ 
         . . . 
      ], 
      cTemplate: function() { 
        return { 
          template: Vue.component("columnTemplate", { 
            template: `<div v-on:click="headerclicked($event,data).bind(this)"  style="color:red" class="headertemplate"> 
                  {{data.headerText}} 
                </div>`, 
            data: function() { 
              return { 
                data: {} 
              }; 
            }, 
            computed: {}, 
            methods: { 
              headerclickedfunction (e, data)  { 
                console.log(e, data); 
                alert("From HeaderTemplate" + data.field + " " + "Clicked"); 
// here emitting the values when the header is clicked 
               this.$eventHub.$emit("template", data); 
              } 
            } 
          }) 
        }; 
      } 
    }; 
  }, 
  methods: { 
// here we can listen the values when the header is clicked 
    getTemplateValuefunction(e) { 
     alert("From root" + e.field + " " + "Clicked"); 
//here you can perform your actions 
    }, 
    load: function() { 
//adding listener 
      this.$eventHub.$on("template"this.getTemplateValue); 
    }, 
    destroyed: function() { 
//removing listener 
      this.$eventHub.$off("template"this.getTemplateValue); 
    } 
  }, 
  provide: { 
    grid: [PageFilterSortEditToolbar] 
  } 
}; 
</script> 
<style> 
@import "https://cdn.syncfusion.com/ej2/material.css"; 
</style> 
 
 

Please let us know, if you need further assistance. 

Regards, 
Manivel 



AM Amos May 22, 2020 11:25 PM UTC

Thank you for the tip. Before using it, a question.

My other communications are done via
this.$root.$emit(...);
I understand that this is a different context but I was hoping that they have the same root hence emitting will do the trick.
In my case, the relevant method is not triggered.
Is there a way for the components to communicate through $root.emit or eventbus is the only way in this case?
Thanks



AM Amos May 25, 2020 05:40 PM UTC

Your eventbuf implementation is working great.

If there is a way to implement it using this.$root.$emit(...);
Please let me know
Thanks


MS Manivel Sellamuthu Syncfusion Team May 26, 2020 11:41 AM UTC

Hi Amos 

Thanks for your update. 

We are glad that the provided solution is working. 

Unfortunately , we were unable to communicate between components in this.$root, so we suggest you to use the event bus to achieve your requirement. 

Please let us know, if you need further assistance. 

Regards, 
Manivel 


Loader.
Up arrow icon