Add button to GROUP HEADER

2 Answers 117 Views
Grid
Oliver
Top achievements
Rank 1
Oliver asked on 13 Jul 2024, 02:57 PM

How is it possible to add a fully functional icon button in grids Group Header ?

My approach : 

                @(Html.Kendo().Grid<ClaimViewModel>()
                    .Name("dgvClaims")
                    .Columns(columns =>
                    {
                        columns.Command(command => command.Custom("Vorgang hinzufügen").IconClass("save").Click("showDetails")).Width(300);
                        columns.Bound(p => p.Id).Filterable(false).Visible(false);
                        @* columns.Bound(p => p.ClaimId).ClientGroupHeaderTemplate(@"<div>Alfred Mustermann</div><div><button name=""textButton""  theme-color=""ThemeColor.Primary"" type=""button"" icon=""arrow-rotate-cw"" on-click=""onClick"">Add Button</button></div>"); *@
                        columns.Bound(p => p.ClaimId).ClientGroupHeaderTemplate(@"<div>
                                                                                    <div>Alfred Mustermann</div>
                                                                                    <kendo-button name=""textButton"" type=""button"" theme-color=""ThemeColor.Primary"">Add Button</kendo-button>
                                                                                  </div>");
                        columns.Bound(p => p.VnName).Width(300);
                        columns.Bound(p => p.ClaimState).Title("Status").Width(100);
                        columns.Bound(p => p.ClaimnumberInsurance).Title("Schadennummer VU").Width(150);
                        columns.Bound(p => p.ClaimnumberRisktaker).Title("Schadennummer Risikoträger").Width(150);
                        columns.Bound(p => p.ClaimFriendlyName).Title("Beschreibung").Width(200);
                        columns.Bound(p => p.ClaimDate).Title("Schadendatum").Format("{0:dd.MM.yyyy}");
                        columns.Bound(p => p.ClaimItemReference).Title("Verweis auf Mappeneintrag").Width(200);
                        columns.Bound(p => p.ClaimItemReferenceType).Title("Eintragstyp").Width(150);
                        columns.Bound(p => p.ClaimItemRemark).Title("Bemerkungen").Width(150);
                    
                    })
                    .Selectable(s => s.Mode(GridSelectionMode.Single)
                    .Type(GridSelectionType.Row))
                    .Pageable()
                    .Sortable()
                    .Scrollable()
                    .Filterable()
 
                   .HtmlAttributes(new { style = "height:650px;" })
                   .Events(events => events.Change("onChangeCustomerGrid"))
                   .DataSource(dataSource => dataSource.Ajax()

2 Answers, 1 is accepted

Sort by
0
Accepted
Ivaylo
Telerik team
answered on 22 Jul 2024, 01:07 PM

Hi Oliver,

Thank you for the details provided.

I assume that you want to get the current group header element. To do this, we can use the "event" parameter in the "onClick" Event handler. The event will point to the button of the grid header template. So you can get the parent of the button, that way you will get the whole current group header.

event.target.parentNode

Please note, that you need to add the event in the button onclick event in the handle, like this: 

<button class='k-button k-button-md k-rounded-md k-button-solid k-button-solid-base' onclick='onClick(event)'><i class='fa fa-home'></i>Click me</button>

Furthermore, I have prepared a sample REPL, so you can test the logic and observe its functionality:

Feel free to correct me if I misunderstood the requirements, and if this is not the desired behavior, please provide more information, and we will do our best to assist you.

Best Regards,
Ivaylo
Progress Telerik

Do you have a stake in the designеr-developer collaboration process? If so, take our survey to share your perspective and become part of this global research. You’ll be among the first to know once the results are out.
-> Start The State of Designer-Developer Collaboration Survey 2024

Oliver
Top achievements
Rank 1
commented on 29 Jul 2024, 09:34 AM

Thank you ...
This was exactly what i was looking for.
0
Ivaylo
Telerik team
answered on 16 Jul 2024, 01:24 PM

Hello Oliver,

Thank you for the provided information! 

In order to achieve the desired behavior, I would recommend using a plain HTML Button which can be styled by using Telerik UI button CSS classes and manually configuring the onClick Event using the "onclick" attribute of the button.

<button class='k-button k-button-md k-rounded-md k-button-solid k-button-solid-base' onclick='onClick()'><i class='fa fa-home'></i>Click me</button>

For the icon, I recommend using the FontAwesome library with the "i" tag where in the "class" attribute you put the class of the icon you want to use. You can see the icons on the FontAwesome website. https://fontawesome.com/v4/icons/ 

<i class='fa fa-home'></i>

Furthermore, there is a REPL demo, where you can run the code and see how it works. https://netcorerepl.telerik.com/QouhFUbw55WT6Prg55 

Regards,
Ivaylo
Progress Telerik

Stay tuned by visiting our public roadmap and feedback portal pages. If you're new to the Telerik family, be sure to check out our getting started resources, as well as the only REPL playground for creating, saving, running, and sharing server-side code.
Oliver
Top achievements
Rank 1
commented on 19 Jul 2024, 06:59 PM

thank ... That was second approach and i hoped there was a more elegant way out of the box.

If you do so how is it possible to access the grid header content wothin the click event ?

Carlonn
Top achievements
Rank 1
commented on 17 Feb 2025, 12:49 PM | edited

Hello Ivaylo,

 

Is this possible with CSPs? onclick inline attributes are not allowed due to CSPs, so what would be the alternative? I'm having trouble setting it in the OnGroup event:


columns.Bound(p => p.ProjectName).Width(100).ClientGroupHeaderTemplate("<button class='assignProject'>Assign</button>");

...

.Events(events => events
    .Group("onGrouping")
)

function onGrouping(arg) {
    var grid = this;
    var projectGrouping = arg.groups.find(elem => elem.field == "ProjectName");
    console.log(countryGrouping);
    if (!projectGrouping) return;

    grid.table.find("tr").each(function () { // not working unfortunately
        $(this).find(".assignProject").kendoButton({
            icon: "plus",
            click: function (e) {
                e.preventDefault();
                // get the project name that is grouped here and perform logic on it
            }
        });
    });
}


Ivaylo
Telerik team
commented on 20 Feb 2025, 08:36 AM

Hello Oliver,

Thank you for the details provided.

The reason why your code is not working is that the templates have not been rendered yet. To ensure compatibility with the Content Security Policy (CSP), the template should be returned within a JavaScript handler, as demonstrated below:

//C#
columns.Bound(p => p.UnitPrice).Width(100).ClientGroupHeaderTemplateHandler("handler");

//JS
function handler() {
        return `
            <div>Alfred Mustermann</div>
            <button class='button'>Add</button>
        `;
    }

To initialize the buttons, register to the DataBoundevent of the Grid, which is triggered after the data has been rendered. Then, utilize Kendo UI for jQuery to initialize the buttons.

//C#
.Events(e => e.DataBound("onDataBound"))

//JS
function onDataBound(e) {
        $('.button').kendoButton({
            icon: "plus",
            click: onClick
        })
    }

Furthermore, I prepared a sample application where the suggested modifications could be tested:

I hope this information was helpful.

Best Regards,
Ivaylo
Progress Telerik

Carlonn
Top achievements
Rank 1
commented on 20 Feb 2025, 12:57 PM

Hello Ivaylo,

Thanks, the alert works here.

However, outside this sample the necessary functionality is still limited.

I could not find a way to get the data in the handler:

 

Either:

function handler(e) {
    return `
        <div>Product Name: #=ProductName#</div>
        <button class='button'>Add</button>
    `;
}

Or

function handler(e) {
    return `
        <div>Product Name: ${e.data.ProductName}</div>
        <button class='button'>Add</button>
    `;
}

Or ${e.ProductName} or just ${ProductName} seems to be working.

I also checked the documentation, but this options specifically was not thoroughly documented: ClientGroupHeaderTemplateHandler(System.String)

Furthermore, although I can get the whole group header with event.target.parentNode in the on click event, I can't specifically get the grid's grouped value with kendo jQuery syntax.

 

Ivaylo
Telerik team
commented on 25 Feb 2025, 09:06 AM

Hello Oliver,

Thank you for the details provided.

The ClientGroupHeaderTemplate handler provides access to the group value within the event. To use the ProductName value, assign the ClientGroupHeaderTemplateHandler to the ProductName column and retrieve the value through the event value property.

Below is an example demonstrating the implementation:
//C#
columns.Bound(p => p.ProductName).ClientGroupHeaderTemplateHandler("handler");

//JS
function handler(e) {
        return `
            <div>${e.value}</div>
            <button class='button'>Add</button>
        `;
    }

Furthermore, I refactored the REPL from the previous response:

I hope this information was helpful.

Best Regards,
Ivaylo
Progress Telerik
Carlonn
Top achievements
Rank 1
commented on 25 Feb 2025, 12:25 PM

Hello Ivaylo,

Thank you for clearing that up.

 

There's one more part from my comment above that I just want to re-highlight, just to clarify everything:

Furthermore, although I can get the whole group header with event.target.parentNode in the on click event, I can't specifically get the grid's grouped value with kendo jQuery syntax.

Within the onclick:

function onClick(event) {
    alert('clicked');
}

How do I conveniently get the value from here? For example, if I have the button in the ClientGroupHeaderTemplateHandler for ProductName, I want to be able to retrieve that product name value on click of the button. Similarly, if the ClientGroupHeaderTemplateHandler was on the UnitPrice, I would like to be able to access that value in my button on click function.

I have added a debugger to the handler but the most I can see is using event.target.parent().text().trim() but it gives the full line, example, 'Alice Mutton\n            Add', this changes depending on the template I provide in the header, and is not reliable.

I would like a way to reliably retrieve the grouped Value, regardless of how the handler is defined. Is this possible?

Example:

function onClick(event) {
    alert('Value ' + event.group.ProductName + ' is clicked'); // something like this
}

 

Thank you in advance.

Ivaylo
Telerik team
commented on 28 Feb 2025, 08:34 AM

Hello Oliver,

Thank you for the details provided.

In the handler function, the onClick handler can be assigned using the onclick event attribute. This approach ensures that the value is correctly passed to the function. Below is an example demonstrating this behavior:

function handler(e) {
        let value = e.value;

        if (typeof(e.value) === 'string') {
            value = e.value.replace(/'/g, "\\'");
        }

        return `
            <div>${e.value}</div>
            <button onclick="onClick('${value}', event)" class='button'>Add</button>
        `;
    }

function onClick(value, event) {
        alert(value);
    }

Please note that the handler function includes additional logic to handle cases where the value is a string containing an apostrophe, such as Chef Anton's Cajun Seasoning.

Additionally, the sample REPL from the previous response has been refactored:

I hope this information was helpful.

Best Regards,
Ivaylo
Progress Telerik

Carlonn
Top achievements
Rank 1
commented on 28 Feb 2025, 12:27 PM

Hello Ivaylo,

Remember the initial restriction was for this to work with CSPs enabled. Inline attributes are not allowed due to CSPs, so I was trying to figure out an alternative.

 

However, fortunately I have already solved this issue.


function handler(e) {
    return `
        <div class="value">${e.value}</div>
        <button class='group-button'>Add</button>
    `;
}



function onDataBound(e) {
    $(".group-button").kendoButton({
        icon: "plus",
        click: onClick,
    });
}



function onClick(event) {
    var value = event.sender.element.parent().find(".value").text().trim();

    alert(value);
}

 

There is no built-in way to manage it so I had to design the template in a way to retrieve it myself.

 

Thank you.

Tags
Grid
Asked by
Oliver
Top achievements
Rank 1
Answers by
Ivaylo
Telerik team
Share this question
or