Custom cell template in hierarchical grid
I have created a one-level data grid and used a custom column template successfully.
Attachment: ProviderGrid.vue_e677953e.zip
Now I have created a three-level hierarchical grid following the example in https://ej2.syncfusion.com/vue/demos/#/material/grid/master-details-export.html.
I need to use custom templates in the lowest level, but the template is not rendering, so I assume I have something configured incorrectly.
I have attached a sample file with the grid code. As you will see, the main "providerGrid" has a child "locationGrid" defined and bound. The locationGrid is defined within the data() function, as in your example. And its child grid, "treatmentGrid," is defined as a variable at the top of the data() function, also as in your example.
The nested grids display correctly - but without the rendered template (editTemplate) specified in the second column of the treatmentGrid. Since the grid is being defined as a variable here, there is no way to use binding syntax. (:template), and the values must be prefixed with "this."
The nested grids display correctly - but without the rendered template (editTemplate) specified in the second column of the treatmentGrid. Since the grid is being defined as a variable here, there is no way to use binding syntax. (:template), and the values must be prefixed with "this."
I have tried this three ways:
- As shown in my code, using a template literal created within the data() function and referring to it in the column definition, which works fine on a single-level grid, but does not render in the lower level.
- By placing the same template literal code in the column definition itself. This causes the treatmentGrid to show a "No records" message.
- By referring to a Vue file imported into the main file. This approach also works fine on a single-level grid, but on the nested grid also causes a "No records" message.
Could you please review the file I sent and suggest how to create and use a custom column template in a nested grid?
Thanks in advance for your help.
Attachment: ProviderGrid.vue_e677953e.zip
SIGN IN To post a reply.
6 Replies
1 reply marked as answer
SM
Shalini Maragathavel
Syncfusion Team
September 29, 2020 11:56 AM UTC
Hi Tom,
Greetings from Syncfusion Support.
Based on your query we found that you want to bind the column template to the nested Grid. You can achieve your requirement of binding the column template to the Hierarchy Grid as demonstrated in the below code snippet,
|
<div>
<e-columns>
<e-column
headerText="Employee Image"
width="150"
textAlign="Center"
:template="cTemplate"
></e-column>
...
</e-columns>
<script>
var itemVue = Vue.component("itemTemplate", {
template: `<span>hi</span>`,
data() {
return {
data: {},
};
},
});
export default Vue.extend({
data: () => {
let secondChildGrid = {
dataSource: customerData,
queryString: "CustomerID",
columns: [
{
headerText: "Custom template",
textAlign: "Right",
template: function () {
return {
template: itemVue,
};
},
width: 75,
},
...
],
childGrid: {
dataSource: hierarchyOrderdata,
queryString: "CustomerID",
columns: [
{
headerText: "Custom template",
textAlign: "Right",
template: function () {
return {
template: itemVue,
};
},
};
return {
parentData: employeeData.slice(0, 5),
cTemplate: function () {
return {
template: Vue.component("columnTemplate", {
template: `<div class="image">
hi
</div>`,
data: function () {
return {
data: {},
};
},
computed: {
image: function () {
return "./" + this.data.EmployeeID + ".png";
},
altImage: function () {
return this.data.EmployeeID;
},
childGrid: {
dataSource: orderDatas,
queryString: "EmployeeID",
columns: [
{
headerText: "Custom template",
template: function () {
return {
template: itemVue,
};
},
},
...
],
childGrid: secondChildGrid,
},
});
</script>
|
Please find the below sample for more information.
Please get back to us if you need further assistance.
Regards,
Shalini M.
Marked as answer
TM
Tom McNeer
October 1, 2020 08:03 PM UTC
I need to go one step further with this. I have created a three-level grid that includes custom cell templates, according to your examples. The display of everything works perfectly. However, I'm struggling to properly handle events from the custom templates in the third-level.
In this ticket, https://www.syncfusion.com/forums/158033/data-in-column-template, you helped me understand how to implement a global event bus to listen for events within the grid. That technique is working correctly, using e.target or e.element in obtaining row data for processing, in a single-level grid.
However, I have not been able to successfully reference the grid when the event is emitted by the third-level grid.
However, I have not been able to successfully reference the grid when the event is emitted by the third-level grid.
I receive the error "TypeError: Cannot read property 'getRowObjectFromUID' of undefined."
The following code is within a parent component, ProviderGrid.vue.
The top-level grid is defined as:
As in your examples, the second-level grid is defined and returned within the data() function as follows:
The third-level grid is defined as a variable at the top of the data() function, as in your example:
<ejs-grid
id="pGrid"
ref="providerGrid"
:created="gridCreated"
:childGrid="locationGrid"
:dataSource="providerData.providers"
:allowFiltering="false"
:allowExcelExport="true"
:allowPdfExport="true"
:allowPaging="true"
:pageSettings="pageSettings"
:allowTextWrap="true"
:allowSorting="false"
:enableAltRow="false"
:toolbar="toolbar"
:toolbarClick="toolbarClick"
:sortSettings="sortSettings"
:rowDataBound="rowDataBound"
>
<e-columns>
<e-column field="Provider" headerText="Provider"></e-column>
</e-columns>
</ejs-grid>
As in your examples, the second-level grid is defined and returned within the data() function as follows:
locationGrid: {
dataSource: this.providerData.locations,
queryString: 'ProviderID',
enableAltRow: false,
columns: [{ field: 'Location', headerText: 'Location' }],
childGrid: treatmentGrid,
rowDataBound: this.locRowDataBound
}
The third-level grid is defined as a variable at the top of the data() function, as in your example:
let treatmentGrid = {
ref: 'tGrid',
dataSource: this.providerData.treatments,
queryString: 'LocationID',
rowDataBound: this.treatmentRowDataBound,
enableAltRow: false,
columns: [
{
headerText: 'Treatment',
width: '300',
template: function() {
return {
template: TreatmentDescColumn
}
}
},
{
headerText: '',
width: '100',
template: function() {
return {
template: TreatmentEditColumn
}
}
},
{
headerText: 'Status',
textAlign: 'center',
width: '80',
template: function() {
return {
template: StatusEditColumn
}
}
},
{
field: 'ApprovalDate',
headerText: 'Appr. Date',
format: 'yMd',
type: 'date',
textAlign: 'center',
width: '90'
},
{
field: 'ProcedureCreator',
headerText: 'Created By',
width: '100'
},
{
headerText: 'Auth. Code (Resend)',
width: '140',
template: function() {
return {
template: ApprovalCodeColumn
}
}
},
{
field: 'ScheduledDate',
headerText: 'Sched. Date',
format: 'yMd',
type: 'date',
textAlign: 'center',
width: '90'
},
{
field: 'TreatmentDate',
headerText: 'Trtmt. Date',
format: 'yMd',
type: 'date',
textAlign: 'center',
width: '90'
},
{
field: 'TNoteDisplay',
headerText: 'Note Rcvd.',
width: '90',
textAlign: 'center'
},
{
field: 'TNoteRead',
headerText: 'Note Read',
width: '90',
textAlign: 'center'
},
{
field: 'Estimate',
headerText: 'Estimate',
textAlign: 'right',
width: '100',
format: 'C2',
type: 'number'
},
{
field: 'Billed',
headerText: 'Billed',
textAlign: 'right',
width: '100',
format: 'C2',
type: 'number'
},
{
field: 'Paid',
headerText: 'Paid',
textAlign: 'right',
width: '100',
format: 'C2',
type: 'number'
}
]
}
The error comes when events are emitted by the custom templates in the third-level. As an example, the following is handled within the created() function of the top-level grid:
this.$nuxt.$on('show-treatment-detail', this.showTreatmentDetail)
The event fires the correct local method:
The local rowData function looks to the grid for the row:
... but this is where the error occurs. I have tried the reference above, using the ref value of the top-level grid, trying to walk down the child grids. I have also tried ...
... attempting to access a ref set when the treatmentGrid is created ...
.. but this fails also.
Could you please help me understand how to access the row correctly? FYI, the same functions work when the event comes from a single-level grid. In the example above, the e.target is the correct reference.
Thanks very much for your help.
showTreatmentDetail(e) {
try {
let data = this.rowData(e.target)
this.$emit('open-treatment-details', data)
} catch (error) {
console.log(error)
}
}
The local rowData function looks to the grid for the row:
rowData(target) {
let rowObj = this.$refs.providerGrid.childGrid.childGrid.ej2Instances.getRowObjectFromUID(
closest(target, '.e-row').getAttribute('data-uid')
)
return rowObj.data
}
let rowObj = this.$refs.tGrid.ej2Instances.getRowObjectFromUID(
closest(target, '.e-row').getAttribute('data-uid')
)
return rowObj.data
let treatmentGrid = {
ref: 'tGrid',
.. but this fails also.
Could you please help me understand how to access the row correctly? FYI, the same functions work when the event comes from a single-level grid. In the example above, the e.target is the correct reference.
Thanks very much for your help.
TM
Tom McNeer
October 3, 2020 01:47 PM UTC
I have finally realized that my problem is that there are multiple grids created dynamically, so hard references such as I've tried won't work.
But the help I need is the same: how to "find" the correct grid in order to work with its row data.
MS
Manivel Sellamuthu
Syncfusion Team
October 6, 2020 10:56 AM UTC
Hi Tom,
Thanks for your update.
Query: how to "find" the correct grid in order to work with its row data.
We have analyzed your query and you can find the correct grid based on the target element.
In the below code example we are listening the event in the top level Grid’s(ParentGrid) created event. The column template has been bound with click event and the same template(itemVue) is applied to all the Child grids. So, while clicking the template we can get the corresponding row details from the grid. Please refer the below code example and sample for more information.
|
<template>
<div class="col-lg-12 control-section">
<div>
<ejs-grid
:dataSource="parentData"
:childGrid="childGrid"
:allowSorting="true"
:created="created"
>
</ejs-grid>
</div>
</div>
</template>
<script>
import Vue from "vue";
import {
GridPlugin,
DetailRow,
Sort,
parentsUntil,
} from "@syncfusion/ej2-vue-grids";
Vue.prototype.$eventHub = new Vue();
Vue.use(GridPlugin);
export default Vue.extend({
data: () => {
let secondChildGrid = {
dataSource: customerData,
queryString: "CustomerID",
columns: [
{
headerText: "Custom template",
textAlign: "Right",
template: function () {
return {
template: itemVue,
};
},
width: 75,
},
{
field: "CustomerID",
headerText: "Customer ID",
textAlign: "Right",
width: 75,
},
{ field: "Address", headerText: "Address", width: 120 },
{ field: "Country", headerText: "Country", width: 100 },
],
childGrid: {
dataSource: hierarchyOrderdata,
queryString: "CustomerID",
columns: [
{
headerText: "Custom template",
textAlign: "Right",
template: function () {
return {
template: itemVue,
};
},
width: 75,
},
{
field: "OrderID",
headerText: "Customer ID",
textAlign: "Right",
width: 75,
},
{ field: "ShipCountry", headerText: "Country", width: 100 },
],
},
};
return {
parentData: employeeData.slice(0, 5),
cTemplate: function () {
return {
template: Vue.component("columnTemplate", {
template: `<div class="image">
hi
</div>`,
data: function () {
return {
data: {},
};
},
computed: {
image: function () {
return "./" + this.data.EmployeeID + ".png";
},
altImage: function () {
return this.data.EmployeeID;
},
},
}),
};
},
childGrid: {
dataSource: orderDatas,
queryString: "EmployeeID",
allowPaging: true,
pageSettings: { pageSize: 6, pageCount: 5 },
columns: [
{
headerText: "Custom template",
template: function () {
return {
template: itemVue,
};
},
textAlign: "Right",
width: 120,
},
{
field: "OrderID",
headerText: "Order ID",
textAlign: "Right",
width: 120,
},
{ field: "ShipCity", headerText: "Ship City", width: 120 },
{ field: "Freight", headerText: "Freight", width: 120 },
{ field: "ShipName", headerText: "Ship Name", width: 150 },
],
childGrid: secondChildGrid,
},
};
},
methods: {
created: function (args) {
//here we are listening the event
this.$eventHub.$on("communicate", this.getRowDetails);
},
getRowDetails: function (e) {
// here we can get the row details
console.log(e);
},
},
provide: {
grid: [DetailRow, Sort],
},
});
var itemVue = Vue.component("itemTemplate", {
template: `<span v-on:click="handleClick($event)">hi</span>`,
data() {
return {
data: {},
};
},
methods: {
handleClick: function (args) {
// here we are obtaining the grid instance dynamically based on the target
var grid = parentsUntil(args.target, "e-grid").ej2_instances[0];
// getting the row details
var rowInfo = grid.getRowInfo(args.target);
// emitting the row details
this.$eventHub.$emit("communicate", rowInfo);
},
},
});
</script> |
Please let us know, if you need further assistance.
Regards,
Manivel
TM
Tom McNeer
October 6, 2020 01:27 PM UTC
Thank you for the very clear example. I'm always impressed with the thoroughness of your support. I think you can finally close this one out.
AG
Ajith Govarthan
Syncfusion Team
October 7, 2020 02:09 PM UTC
Hi Tom,
Thanks for your update.
We are happy to hear that your issue has been resolved.
Please get back to us if you need further assistance.
Regards,
Ajith G.
SIGN IN To post a reply.
- 6 Replies
- 4 Participants
- Marked answer
-
TM Tom McNeer
- Sep 25, 2020 03:21 PM UTC
- Oct 7, 2020 02:09 PM UTC