This is a migrated thread and some comments may be shown as answers.

Bind table items to Grid data inside TabStrip

9 Answers 944 Views
Grid
This is a migrated thread and some comments may be shown as answers.
Peter
Top achievements
Rank 1
Peter asked on 25 Jul 2018, 09:58 AM

Setup: Master-Detail with TabStrip and Grid.

Inside a TabStrip item, which is inside a ClientDetailTemplate of a Grid, I need to have an editable Grid.

The Model for the ClientDetail contains 20 columns, but only three of them must be editable, so I want to put these three columns in an editable Grid. I want to display the rest of the (non-editable) columns in a <div><ul><li> setup, so I can style it in a multi column vertically setup for better readability (putting them as readonly columns inside the Grid would cause a huge horizontal layout).

Is there a way to bind the <li> #= items # </li> to the datasource that is bind to the Grid inside the TabStrip? It looks like I can only bind to the data that is in the Master that contains the ClientDetailTemplate.

The detail data inside the Grid, which is inside the TabStrip item, has its own datasource and this is working as expected. I just need to know how to bind the remaining values to some HTML.

TIA

9 Answers, 1 is accepted

Sort by
0
Alex Hajigeorgieva
Telerik team
answered on 27 Jul 2018, 08:53 AM
Hi, Peter,

It is possible to achieve the desired outcome to obtain the non-editable properties of the detail Kendo UI Grid and visualize them in a different way. In fact, I can think of several different ways to do that so I am not sure which would be the best for you. 

- You could add a requestEnd event handler to the detail grid data source and take the data as it arrives. It does not matter if the grid has only three columns if the full model is sent from the server, you can access it:

https://docs.telerik.com/kendo-ui/api/javascript/data/datasource/events/requestend

- If you wish to show the extra data at a later stage, you can always get hold of it via the detail grid data source with the data() method at any time. The non-visualized properties will still be there:

https://docs.telerik.com/kendo-ui/api/javascript/data/datasource/methods/data

- You could use a shared data source and display the extra properties in a ListView which has a highly customisable template:

https://demos.telerik.com/aspnet-mvc/datasource/shared-datasource
https://demos.telerik.com/aspnet-mvc/listview/remote-data-binding

- You could use the data bound event of the grid, get the data items and bind them to the HTML template with the help of Kendo Template and kendo.bind()

https://docs.telerik.com/kendo-ui/framework/templates/overview
https://docs.telerik.com/kendo-ui/framework/mvvm/bindings/source#source-binding-to-array

Let me know which of these options seem most applicable to your scenario and I can provide more in-depth information if necessary.

Kind Regards,
Alex Hajigeorgieva
Progress Telerik
Get quickly onboarded and successful with your Telerik and/or Kendo UI products with the Virtual Classroom free technical training, available to all active customers. Learn More.
0
Peter
Top achievements
Rank 1
answered on 31 Jul 2018, 03:55 PM

Hi Alex, thank you.

My first choice would be to use the shared DataSource with the ListView, because that keeps me in the Kendo MVC extentions approach. Unless you can advise me to better use one of your other suggested approaches? I have tried to get this ListView approach working, but I face some problems.

- Where do I put the DataSource: inside the top level of the page, inside the template script, inside the TabStrip, or even more deep inside the TabStrip items? 
I have tried to get it working when defining the DataSource at the top level but it looks like I can only get a hold on the data that is bound to the Master Grid.Is this correct?

- How can I pass a parameter to the DataSource: it needs to know for which specific record I'm requesting the details, doesn't it?

- When I put the Shared DataSource inside the Items node of the TabStrip it seems to work. However, most of the time (8 out of 10) the detail Grid is showing, but the ListView is not. After a complete refresh it is working but it is very unreliable at this point.

Can you provide me with a MVC example of the setup that I need? Please see the attached sketch for clearification.

Furthermore, if I want to choose another approach, please give me your opinion and some sample code as well.

Thanks!

 

My code so far, sorry if it looks messy:

@(Html.Kendo().Grid<eliXer_POC_01.Models.bkst_overzicht>()
                                    .Name("grid")
                                    .Columns(columns =>
                                    {
                            columns.Bound(c => c.peildatum);
                                        columns.Bound(c => c.idInschrijving).Filterable(ftb => ftb.Cell(cell => cell.Template("customFilter")))                                        ;
                                        columns.Bound(c => c.stamnr)
                                            .Filterable(ftb => ftb
                                            .Cell(cell => cell
                                            .Template("customFilter")
                                            .ShowOperators(true)))
                                            ;
                                        columns.Bound(c => c.achternaam);
                                        columns.Bound(c => c.Nationaliteit);
                                        columns.Bound(c => c.Leeftijd_bij_aanvang).Title("LBA").Filterable(ftb => ftb.Cell(cell => cell.Template("customFilter")))                                        ;
                                        columns.Bound(c => c.Crebo).Filterable(ftb => ftb.Cell(cell => cell.Template("customFilter")))                                        ;
                                        columns.Bound(c => c.Omschrijving_crebo).Title("Omschr.")                                        ;
                                        columns.Bound(c => c.Leerweg);
                                        columns.Bound(c => c.Locatie);
                                        columns.Bound(c => c.groep);
                                        columns.Bound(c => c.PRS_STATUS).Width(70).Title("PRS").ClientTemplate(
                                                      "# if (PRS_STATUS == 'A') { #" +
                                                          "<img src='" + Url.Content("~/Content/icons/") + "ja.png' alt='#= PRS_STATUS # icon' />" +
                                                      "# } else if (PRS_STATUS == 'B') { #" +
                                                          "<img src='" + Url.Content("~/Content/icons/") + "beoordelen.png' alt='#= PRS_STATUS # icon' />" +
                                                           "# } else { #" +
                                                          "<img src='" + Url.Content("~/Content/icons/") + "nee.png' alt='#= PRS_STATUS # icon' />" +
                                                      "# } #"
                                                  );
 
                                        columns.Bound(c => c.INS_STATUS).Width(70).Title("INS").ClientTemplate(
                                                      "# if (INS_STATUS == 'A') { #" +
                                                          "<img src='" + Url.Content("~/Content/icons/") + "ja.png' alt='#= INS_STATUS # icon' />" +
                                                      "# } else if (INS_STATUS == 'B') { #" +
                                                          "<img src='" + Url.Content("~/Content/icons/") + "beoordelen.png' alt='#= INS_STATUS # icon' />" +
                                                           "# } else { #" +
                                                          "<img src='" + Url.Content("~/Content/icons/") + "nee.png' alt='#= INS_STATUS # icon' />" +
                                                      "# } #"
                                                  );
                                        columns.Bound(c => c.OOK_STATUS).Width(70).Title("OOK").ClientTemplate(
                                              "# if (OOK_STATUS == 'A') { #" +
                                              "<img src='" + Url.Content("~/Content/icons/") + "ja.png' alt='#= OOK_STATUS # icon' />" +
                                              "# } else if (OOK_STATUS == 'B') { #" +
                                              "<img src='" + Url.Content("~/Content/icons/") + "beoordelen.png' alt='#= OOK_STATUS # icon' />" +
                                              "# } else { #" +
                                              "<img src='" + Url.Content("~/Content/icons/") + "nee.png' alt='#= OOK_STATUS # icon' />" +
                                              "# } #"
                                              );
                                        columns.Bound(c => c.OB_STATUS).Width(70).Title("OB").ClientTemplate(
                                              "# if (OB_STATUS == 'A') { #" +
                                              "<img src='" + Url.Content("~/Content/icons/") + "ja.png' alt='#= OB_STATUS # icon' />" +
                                              "# } else if (OB_STATUS == 'B') { #" +
                                              "<img src='" + Url.Content("~/Content/icons/") + "beoordelen.png' alt='#= OB_STATUS # icon' />" +
                                              "# } else { #" +
                                              "<img src='" + Url.Content("~/Content/icons/") + "nee.png' alt='#= OB_STATUS # icon' />" +
                                              "# } #"
                                              );
                                        columns.Bound(c => c.BPVO_STATUS).Width(70).Title("BPVO").ClientTemplate(
                                              "# if (BPVO_STATUS == 'A') { #" +
                                              "<img src='" + Url.Content("~/Content/icons/") + "ja.png' alt='#= BPVO_STATUS # icon' />" +
                                              "# } else if (BPVO_STATUS == 'B') { #" +
                                              "<img src='" + Url.Content("~/Content/icons/") + "beoordelen.png' alt='#= BPVO_STATUS # icon' />" +
                                              "# } else { #" +
                                              "<img src='" + Url.Content("~/Content/icons/") + "nee.png' alt='#= BPVO_STATUS # icon' />" +
                                              "# } #"
                                              );
 
                                        columns.Bound(c => c.AAR_STATUS).Width(70).Title("AAR").ClientTemplate(
                                              "# if (AAR_STATUS == 'A') { #" +
                                              "<img src='" + Url.Content("~/Content/icons/") + "ja.png' alt='#= OB_STATUS # icon' />" +
                                              "# } else if (AAR_STATUS == 'B') { #" +
                                              "<img src='" + Url.Content("~/Content/icons/") + "beoordelen.png' alt='#= OB_STATUS # icon' />" +
                                              "# } else { #" +
                                              "<img src='" + Url.Content("~/Content/icons/") + "nee.png' alt='#= OB_STATUS # icon' />" +
                                              "# } #"
                                              );
                                    })
                                    .ColumnMenu()
                                    .Pageable()
                                    .Navigatable()
                                    .Selectable(selectable =>
                                    {
                                        selectable.Mode(GridSelectionMode.Single);
                                        selectable.Type(GridSelectionType.Row);
                                    })
                                    .Sortable(sortable =>
                                    {
                                        sortable.SortMode(GridSortMode.SingleColumn);
                                    })
                                    .Filterable(filterable => filterable
                                        .Mode(GridFilterMode.Row)
                                        )
                                    .Scrollable()
                                    .DataSource(dataSource => dataSource
                                    .Ajax()
                                    .PageSize(50)
                                    .Read(read => read.Action("bkst_overzicht_Read", "Overzicht"))
                                    )
                                    .HtmlAttributes(new { style = "height:840px;" })
                                    .Resizable(resize => resize.Columns(true))
                                    .ClientDetailTemplateId("eliXertemplate")
)
 
@*Detailtemplate met tabs*@
<script id="eliXertemplate" type="text/kendo-tmpl">
    @(Html.Kendo().TabStrip()
                                                .Name("tabStrip_#=idInschrijving#")
                                                .SelectedIndex(0) 
                                                .Animation(animation => animation.Open(open => open.Fade(FadeDirection.In)))
                                                .Items(items =>
                                                {
                                                    items.Add().Text("Persoons").Content(
 
                                    @<div id="myWrapper">
                                        <div id="myLeft">
                                            @*hardcoded PDF for now*@
                                            <embed src="PDF/xtendis.pdf" width='1000' height='600' type='application/pdf'>
                                        </div>
                                        <div id="myRight">
                                            @(Html.Kendo().DataSource<eliXer_POC_01.Models.bkst_PRS>()
                                                .Name("dataSourcePersoonDetails")
                                                .Ajax(dataSource => dataSource
                                                .Read(read => read.Action("DetailTemplate_HierarchyBinding_PRS", "Grid3", new { idLeer = "#=idLeer#" }))
                                                .ServerOperation(false)
                                                .PageSize(20)
                                                .Model(model =>
                                                {
                                                    model.Id(p => p.idLeer);
                                                })
                                                )
                                            )
                                            @(Html.Kendo().ListView<eliXer_POC_01.Models.bkst_PRS>()
                                                                    .Name("listView")
                                                                    .TagName("div")
                                                                    .ClientTemplateId("template")
                                                                    .DataSource("dataSourcePersoonDetails")
                                                                    .ToClientTemplate()
                                            )
                                            @(Html.Kendo().Grid<eliXer_POC_01.Models.bkst_PRS>()
                                .Name("grid_#=idLeer#") // template expression, to be evaluated in the master context
                                .Editable()
                                .Columns(columns =>
                                {
                                    columns.Bound(o => o.idLeer);
                                    columns.Bound(o => o.stamnr);
                                    columns.Bound(o => o.PersoonId).Width(150);
                                    columns.Bound(o => o.Geslacht);;
 
                                })
                                .HtmlAttributes(new { style = "margin:10px;" })
                                .DataSource("dataSourcePersoonDetails")
                                .ToClientTemplate()
                                            )
                                        </div>
                                        <div id="myCleared"></div>
                                    </div>
                                                                );
                                                })
                                                .ToClientTemplate())
</script>
 
 
<script>
    function customFilter(args) {
        args.element.kendoNumericTextBox({
            decimals: 0,
            format: "n0",
            spinners: false
        });
    }
</script>
 
 
<script type="text/x-kendo-tmpl" id="template">
    <div class='employee-details' style="float:left;">
        <ul>
            <li><label>Stamnummer:</label>#= stamnr #</li>
            <li><label>idLeer:</label>#= idLeer #</li>
            <li><label>PersoonId:</label>#= PersoonId #</li>
            <li><label>Roepnaam:</label>#= Roepnaam #</li>
            <li><label>Voornamen:</label>#= Officiële_voornamen #</li>
            <li><label>Tussenvoegsel:</label>#= Tussenvoegsel #</li>
            <li><label>Achternaam:</label>#= Officiële_achternaam #</li>
 
        </ul>
    </div>
    <div class='employee-details'>
        <ul>
            <li><label>Geslacht:</label>#= Geslacht #</li>
            <li><label>Geboortedatum:</label>#= Geboortedatum #</li>
            <li><label>Geboorteplaats:</label>#= Geboorteplaats #</li>
            <li><label>Geboorteland:</label>#= Geboorteland #</li>
            <li><label>Nationaliteit:</label>#= Nationaliteit #</li>
            <li><label>Scandatum:</label>#= Scandatum_identiteitsbewijs #</li>
            <li><label>XID:</label>#= XID_identiteitsbewijs #</li>
        </ul>
    </div>
    <div>Laatste import: #= importdatumBIM #</div>
 
</script>
0
Alex Hajigeorgieva
Telerik team
answered on 01 Aug 2018, 02:57 PM
Hello, Peter,

I have prepared an example for your reference with the requested approach.

The data source is defined outside of the TabStrip and the data source's ToClientTemplate() is called. Here is the detail template and I have highlighted the important bits - such as keeping a unique name for each grid, tab strip, listview and data source in the detail view:

<script id="detail-template" type="text/kendo-tmpl">
    @(Html.Kendo().DataSource<GridDetailsWithSharedDataSource.Models.OrderDetailViewModel>()
       .Name("dataSourceOrderDetails#=OrderID#")
       .Ajax(a => a.Read(read => read.Action("OrdersDetails_Read", "Grid", new { orderID = "#=OrderID#" })).ServerOperation(false).PageSize(3))
       .ToClientTemplate()
    )
 
    @(Html.Kendo().TabStrip()
               .Name("tabStrip_#=OrderID#")
               .SelectedIndex(0)
               .Animation(animation => animation.Open(open => open.Fade(FadeDirection.In)))
               .Items(items =>
               {
                   items.Add().Text("Persoons").Content(@<text>
                    @(Html.Kendo().ListView<GridDetailsWithSharedDataSource.Models.OrderDetailViewModel>()
                      .Name("listView#=OrderID#")
                      .TagName("div")
                      .ClientTemplateId("listview-template")
                      .DataSource("dataSourceOrderDetails#=OrderID#")
                      .Pageable()
                      .ToClientTemplate()
                    )
                    @(Html.Kendo().Grid<GridDetailsWithSharedDataSource.Models.OrderDetailViewModel>
                              ()
                              .Name("grid_#=OrderID#") // template expression, to be evaluated in the master context
                              .Columns(columns =>
                              {
                                         columns.Bound(o => o.OrderID).Width(110);
                                         columns.Bound(o => o.OrderDate).Format("{0:D}").Width(150);
                                     })
                              .DataSource("dataSourceOrderDetails#=OrderID#")
                              .Pageable()
                              .Sortable()
                              .ToClientTemplate()
                    )
                </text>);
            }).ToClientTemplate()
    )
</script>

Naturally, since the grid and the listview utilize a shared data source, paging one pages the other etc.

Could you please clarify this question:

I have tried to get it working when defining the DataSource at the top level but it looks like I can only get a hold on the data that is bound to the Master Grid.Is this correct?

In case you need to get hold of items which are available in the child context, then the template should be escaped, e.g.:

\\#= ShipAddress \\# --> escaped template expression, to be evaluated in the child/detail context
"#=EmployeeID#   --> expresion will be evaluated in the parent context

Finally, since this is a public forum, the Kendo.Mvc.dll in the lib folder is a trial one so you may need to replace it or change the reference to the one on your machine.

Regards,
Alex Hajigeorgieva
Progress Telerik
Get quickly onboarded and successful with your Telerik and/or Kendo UI products with the Virtual Classroom free technical training, available to all active customers. Learn More.
0
Peter
Top achievements
Rank 1
answered on 01 Aug 2018, 07:31 PM

Great Alex, I'm getting close!

A few more questions:

1. inside the client template I have a datefield like this:
<div>Last import: #= importdate #</div>
How do I format this in dd-mm-yyyy notation?

2. How can I make this three Grid fields inside the detail Grid editable, do I use the same syntax as with a normal Grid? I need a model ID I guess, how can I send this to the controller? Do I use the same shared datasource for this?

3. I see you use ServerOperation(false) in your example.Can you explain why this is the best option?

You asked me to clarify "I have tried to get it working when defining the DataSource at the top level....", I meant to say that in that specific case I defined the shared Datasource on the very top of the code, not inside the ClientDetailTemplate. I'm still a bit confused where to put this definition of the datasource and why. I presume it has to reside inside the ClientDetailTemplate. It is working now, anyway.

And the last question for now:
"In case you need to get hold of items which are available in the child context, then the template should be escaped, e.g......"

Do you mean I can get a hold of these items anywhere in my code, e.g. inside the Master Grid?

Thanks again!

Peter

 

 

0
Alex Hajigeorgieva
Telerik team
answered on 03 Aug 2018, 10:01 AM
Hi, Peter,

I am glad to hear that we are getting closer to achieving the desired outcome. Please find my answers to the questions below:

1. inside the client template I have a datefield like this:
<div>Last import: #= importdate #</div>
How do I format this in dd-mm-yyyy notation?

You can use kendo.toString() to format the date and depending on the culture, you can pass a predefined format like "d" or "D":

https://docs.telerik.com/kendo-ui/framework/globalization/dateformatting

 If the current culture provides a different format, you can pass the custom one like this:

#= kendo.toString(importdate, "dd-MM-yyyy") #

2. How can I make this three Grid fields inside the detail Grid editable, do I use the same syntax as with a normal Grid? I need a model ID I guess, how can I send this to the controller? Do I use the same shared datasource for this?

The same rules will apply for the detail grid as they do for the master. You would need to specify a model id and an update action method. You can send the child properties as additional Data() or as shown in the demo. If the property is a child property, then use two backslashes, if it is from the master row, do not use backslashes(this is true for single level hierarchy)

Option 1:

https://docs.telerik.com/aspnet-mvc/helpers/grid/faq#how-to-send-values-to-my-action-method-when-binding-the-grid

Option 2:

.Update(read => read.Action("HierarchyUpdate", "Grid", new { parentField = "#=ParentField#", childField = "\\#=ChildField\\#" }))

3. I see you use ServerOperation(false) in your example.Can you explain why this is the best option?

I chose server operation false so that the data source would request all items at once during the read. It is just because I had so few items, it did not make sense to make more than one request to get them.

Thank you for clarifying regarding the positioning of the data source. If it is left outside of the client template, then it will be a single shared data source for all the listviews and the detail grids which would defy the purpose of the existence of the exact same content for every detail row. In order to be able to link it with the correct parent item and give it a unique id, I believe it belongs in the client template. Having it there will create as many data sources as there are initialized detail rows. (the details are lazy loaded).

Finally, to get hold of the child data source data item values, you would need the child to have been initialized. Then you can look for the nearest element in a detail cell with the attribute of data-role="grid". Let me know what you need to accomplish and I can propose a way to do it if there is one.

Kind Regards,
Alex Hajigeorgieva
Progress Telerik
Get quickly onboarded and successful with your Telerik and/or Kendo UI products with the Virtual Classroom free technical training, available to all active customers. Learn More.
0
Peter
Top achievements
Rank 1
answered on 21 Nov 2018, 02:03 PM

Hi Alex,

It's been a while since I've worked on this issue, today I picked it up again. I have one more question: Instead of the default  horizontal layout of the Grid, I need a vertical layout because of the many items in the Model. I don't want the user to scroll horizontal. See attached picture:

The red R means readonly data. The green W means editable data. Column 8 needs to be a dropdownl list of <List> items from the ViewModel. Column 9 needs to be a Yes/No bullet. Column 10 needs to be a multiline textbox. I need this in a separate table, kind of as shown in the picture. For the first table, you've supplied me with enough information how to accomplish this. For the second editable table, I'm still searching for an answer. How can this be done? Can it also be done without a Kendo Grid? Can you please show me how?

TIA

0
Viktor Tachev
Telerik team
answered on 23 Nov 2018, 08:36 AM
Hello Peter,

I have replied to the other thread you have submitted, however, I will also paste the answer here for reference.

By default the Grid displays the data as it is passed from the remote service. It does not alter its structure. In order to implement the behavior you describe the data should be transposed in order for the columns to be shown as rows. The blog post below describes how this functionality can be implemented. 



Let me know how the suggested approach works on your end.

Regards,
Viktor Tachev
Progress Telerik
Get quickly onboarded and successful with your Telerik and/or Kendo UI products with the Virtual Classroom free technical training, available to all active customers. Learn More.
0
Peter
Top achievements
Rank 1
answered on 26 Nov 2018, 08:33 PM

Hi Viktor,

Thanks, I'll look into that, that will take me some time it seems :-).

Can you please tell me up front if it's true that the ASP.NET Core DataSource component doesn't have a ToClientTemplate() method? And if so, how can we use a shared DataSource in a .NET Core project? It needs a hierarchy like this:

Master Grid => Detail Template => TabStrip => Item => ListView (editable) combined with plain HTML (same DataSource) with readonly list items like this: 

<div class='employee-details' style="float:left;">
        <ul>
            <li><label>Stamnummer:</label>#= stamnr #</li>
            <li><label>idLeer:</label>#= idLeer #</li>
            <li><label>PersoonId:</label>#= PersoonId #</li>
            <li><label>Roepnaam:</label>#= Roepnaam #</li>
            <li><label>Voornamen:</label>#= Officiële_voornamen #</li>
            <li><label>Tussenvoegsel:</label>#= Tussenvoegsel #</li>
            <li><label>Achternaam:</label>#= Officiële_achternaam #</li>
  
        </ul>
    </div>
0
Viktor Tachev
Telerik team
answered on 28 Nov 2018, 12:13 PM
Hi Peter,

Please submit each new question in a separate ticket. Thus, the information in a single thread will be consistent and easier to use as reference in the future. Also, when it is a forum post it will be easier for someone facing similar behavior to find a solution.

With that said, if you would like to use a shared DataSource in .NET Core project you can define the DataSource and reference it by name in the widgets that will be using it. Check out the example below that illustrates the approach. 



Regards,
Viktor Tachev
Progress Telerik
Get quickly onboarded and successful with your Telerik and/or Kendo UI products with the Virtual Classroom free technical training, available to all active customers. Learn More.
Tags
Grid
Asked by
Peter
Top achievements
Rank 1
Answers by
Alex Hajigeorgieva
Telerik team
Peter
Top achievements
Rank 1
Viktor Tachev
Telerik team
Share this question
or