Bind complex objects to RadGrid

7 posts, 0 answers
  1. Gioce90
    Gioce90 avatar
    16 posts
    Member since:
    Nov 2015

    Posted 09 May Link to this post

    Hi, I have to create a table to monitor a list of streams.
    The table, as you can see from the attached, must have the following features:

    - The stream description (or name) to be monitored
    - The type (input, output or both)
    - The results of a particular day (and here is the problem)

    It must also be possible:
    - Switch the view from one week to another
    - Change the type of streams to be displayed (View 1 for example shows the customer streams. The View 2 is for suppliers streams)

    The data streams are provided by Web Service, via JSON.

    I planned on doing everything with the RadGrid, but I have some difficulties in its implementation.

    This is the model to pass:

    1.[DataContractFormat]
    2.public class StreamOutputDto : BaseDto
    3.{
    4.    public string Name { get; set; }
    5.    public string Type { get; set; }
    6.    public List<DetailStream> Details { get; set; }
    7.}

     

    Where "DetailStream" is:

    01.public class DetailStream
    02.{
    03.    public string Id { get; set; }
    04.    public DateTime Date { get; set; }
    05.    public int CountInfo { get; set; }
    06.    public StateStream StateInput { get; set; }
    07.    public StateStream StateOutput { get; set; }
    08.    //...
    09.}
    10. 
    11.public enum StateStream
    12.{
    13.    InProgress,
    14.    Received,
    15.    Declined,
    16.    Inexistent
    17.}

     

    So DetailStream is the result of a specific stream in a specific day.
    Details is a list of DetailStream, ie the results of a specific stream in a specific week.

    With Name and Type there are no problems, but I do not know how to manage the list of DetailStream.

     

    This is my current implementation:

    My Web Service:

    01.[ServiceContract]
    02.public interface IMyService
    03.{
    04.    [OperationContract]
    05.    [WebInvoke(
    06.        Method = "POST",
    07.        ResponseFormat = WebMessageFormat.Json)]
    08.    StandardResponse<StreamOutputDto> GetStream(string request);
    09.}
    10. 
    11. 
    12.[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
    13.[MessageLoggingBehavior]
    14.public class MyService : IMyService
    15.{
    16. 
    17.    public StandardResponse<StreamOutputDto> GetStream(string request)
    18.    {
    19.        // TEST CASE:
    20.        StandardResponse<StreamOutputDto> response = new StandardResponse<StreamOutputDto>();
    21.        response.Output = new StreamOutputDto();
    22.        response.Output.Name = "Hi!";
    23.        response.Output.Type = "Input";
    24.        response.Output.Details = new List<DetailStream>();
    25.         
    26.        response.Output.Details.Add(new DetailStream(){
    27.                Id = "1",
    28.                CountInfo = 100,
    29.                Date = DateTime.Today });
    30. 
    31.            response.Output.Details.Add(new DetailStream(){
    32.                Id = "2",
    33.                // Date = yesterday,
    34.                CountInfo = 200 });
    35. 
    36.        return response;
    37.    }
    38. 
    39.}

     

    My WebForm.aspx:

    01.<head>
    03.    <script src="RadGridParser.js"></script>
    04.</head>
    05. 
    06.<body>
    07. 
    08.    <telerik:RadScriptManager runat="server" ID="RadScriptManager1" />
    09.    <telerik:RadSkinManager ID="RadSkinManager1" runat="server" ShowChooser="true"/>
    10.     
    11.    <telerik:RadGrid ID="RadGrid1" RenderMode="Lightweight" ClientDataSourceID="RadClientDataSource1"
    12.             AllowPaging="false" AllowSorting="false" AllowFilteringByColumn="false" PageSize="5" runat="server">
    13. 
    14.        <MasterTableView DataKeyNames="Name" ClientDataKeyNames="Name">
    15.            <Columns>
    16.                <telerik:GridBoundColumn DataField="Name" HeaderText="" DataType="System.String" >
    17.                </telerik:GridBoundColumn>
    18.                <telerik:GridBoundColumn DataField="Type" HeaderText="Tipologia flusso" DataType="System.String">
    19.                </telerik:GridBoundColumn>
    20.                <telerik:GridBoundColumn DataField="Day1" HeaderText="Lunedì">
    21.                </telerik:GridBoundColumn>
    22.                <telerik:GridBoundColumn DataField="Day2" HeaderText="Martedì">
    23.                </telerik:GridBoundColumn>
    24.                <telerik:GridBoundColumn DataField="Day3" HeaderText="Mercoledì">
    25.                </telerik:GridBoundColumn>
    26.                <telerik:GridBoundColumn DataField="Day4" HeaderText="Giovedì">
    27.                </telerik:GridBoundColumn>
    28.                <telerik:GridBoundColumn DataField="Day5" HeaderText="Venerdì">
    29.                </telerik:GridBoundColumn>
    30.            </Columns>
    31.        </MasterTableView>
    32. 
    33.    </telerik:RadGrid>
    34. 
    35.    <telerik:RadClientDataSource ID="RadClientDataSource1" runat="server" AllowBatchOperations="true">
    36.        <ClientEvents OnCustomParameter="ParameterMap" OnDataParse="Parse" />
    37.        <DataSource>
    38.            <WebServiceDataSourceSettings>
    39.                <Select Url="http://soldev/Axa.Sol.Web/ws/Ivass/IvassService.svc/GetFlusso3" DataType="JSON" RequestType="Post" />
    40.            </WebServiceDataSourceSettings>
    41.        </DataSource>
    42.        <Schema ResponseType="JSON">
    43.            <Model ID="StreamModel">
    44.                <telerik:ClientDataSourceModelField FieldName="Name" DataType="String" />
    45.                <telerik:ClientDataSourceModelField FieldName="Type" DataType="String" />
    46.                <telerik:ClientDataSourceModelField FieldName="Day1" DataType="String" />
    47.                <telerik:ClientDataSourceModelField FieldName="Day2" DataType="String" />
    48.                <telerik:ClientDataSourceModelField FieldName="Day3" DataType="String" />
    49.                <telerik:ClientDataSourceModelField FieldName="Day4" DataType="String" />
    50.                <telerik:ClientDataSourceModelField FieldName="Day5" DataType="String" />
    51.            </Model>
    52.        </Schema>
    53.    </telerik:RadClientDataSource>
    54. 
    55.</body>

     

    My RadGridParser.js :

    01.//<![CDATA[
    02.function ParameterMap(sender, args) {
    03.    //If you want to send a parameter to the select call you can modify the if
    04.    //statement to check whether the request type is 'read':
    05.    //if (args.get_type() == "read" && args.get_data()) {
    06.    if (args.get_type() != "read" && args.get_data()) {
    07.        args.set_parameterFormat({ request: kendo.stringify(args.get_data().models) });
    08.    }
    09.}
    10. 
    11.function Parse(sender, args) {
    12.    var response = args.get_response();
    13.    if (response) {
    14.        args.set_parsedData(response.Output);
    15.    }
    16.}
    17. 
    18.function UserAction(sender, args) {
    19.    if (sender.get_batchEditingManager().hasChanges(sender.get_masterTableView()) &&
    20.                !confirm("Any changes will be cleared. Are you sure you want to perform this action?")) {
    21.        args.set_cancel(true);
    22.    }
    23.}
    24. 
    25.//]]>

     

     

     

  2. Gioce90
    Gioce90 avatar
    16 posts
    Member since:
    Nov 2015

    Posted 09 May Link to this post

    Edit:

     

    <Select Url="http://soldev/Axa.Sol.Web/ws/Ivass/IvassService.svc/GetStream" DataType="JSON" RequestType="Post" />

  3. UI for ASP.NET Ajax is Ready for VS 2017
  4. Marin
    Admin
    Marin avatar
    1045 posts

    Posted 10 May Link to this post

    Hello,

    Such type of data is best displayed in the RadGrid when it is setup as a hierarchy - with Name and Type fields on the parent level and the list of DetailStream show as child record. You expand the parent record and see the information for the child record as shown in this demo: http://demos.telerik.com/aspnet-ajax/grid/examples/data-binding/programmatic-hierarchy/defaultcs.aspx

    However hierarchy is not supported with client-side databinding. If you wish to use client-side databinding the data has to be in a flat tabular structure without detail objects. This way you can bind the Day1, Day2, etc, columns to simple objects: like string or number, because a whole DetailStream object cannot be shown in: <telerik:GridBoundColumn DataField="Day1" /> 

    Regards,
    Marin
    Telerik
    Do you need help with upgrading your ASP.NET AJAX, WPF or WinForms projects? Check the Telerik API Analyzer and share your thoughts.
  5. Gioce90
    Gioce90 avatar
    16 posts
    Member since:
    Nov 2015

    Posted 10 May in reply to Marin Link to this post

    Unfortunatly, the hierarchy way is not acceptable. In my company we need something like the image that I have attach before.

    Today I have done some change, so now I have this situation (see the new attach).

    Model (is almost the same):

    [DataContractFormat]
    public class StreamDto : BaseDto
    {
        public string Name { get; set; }
        public string CodCompany { get; set; }
        public string Type { get; set; }
     
        public DetailsStream DayLun { get; set; } // No list? Awful...
        public DetailsStream DayMar { get; set; }
        public DetailsStream DayMer { get; set; }
        public DetailsStream DayGio { get; set; }
        public DetailsStream DayVen { get; set; }
    }
     
    public class DetailsStream
    {
        public string Id { get; set; }
        public int CountScarti { get; set; }
        public string Date { get; set; }
        //... and for states?
    }

     


    My web service (is almost the same):

    [ServiceContract]
    public interface IMyService
    {
        [OperationContract]
        [WebInvoke(
            Method = "POST",
            ResponseFormat = WebMessageFormat.Json)]
        StandardResponse<StreamDto> GetStream();
    }
     
     
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
    [MessageLoggingBehavior]
    public class MyService : IMyService
    {
        public StandardResponse<StreamDto> GetStream()
        {
            var response = new StandardResponse<StreamDto>();
     
            // TEST CASE:
            response.Output = new StreamDto()
            {
                Name = "Stream1",
                CodCompany = "1",
                Type = "Input",
     
                DayLun = new DetailsStream()
                {
                    Id = "1",
                    CountScarti = 10,
                },
     
                DayMar = new DettaglioFlusso()
                {
                    Id = "2",
                    CountScarti = 20,
                },
     
                DayMer = new DettaglioFlusso()
                {
                    Id = "3",
                    CountScarti = 30,
                },
     
                DayGio = new DettaglioFlusso()
                {
                    Id = "4",
                    CountScarti = 40,
                },
     
                DayVen = new DettaglioFlusso()
                {
                    Id = "5",
                    CountScarti = 50,
                }
            };
     
            return response;
        }
    }

     


    My WebForm.aspx (just the changes)

    - the columns of the RadGrid:

    <Columns>
        <telerik:GridBoundColumn DataField="NomeFlusso" HeaderText="" DataType="System.String">
        </telerik:GridBoundColumn>
        <telerik:GridBoundColumn DataField="TipoFlusso" HeaderText="Tipologia flusso" DataType="System.String">
        </telerik:GridBoundColumn>
         
        <telerik:GridTemplateColumn DataField="DayLun" HeaderText="Lunedì">
            <ClientItemTemplate>
                <img src='Arrows-icon.png' alt="" style="vertical-align: middle; margin-right: 7px;" />
                <span>Id:#=DayLunId# </span>
                <span>(#=DayLunCount#)</span>
                <span>#=DayLunData#</span>
            </ClientItemTemplate>
        </telerik:GridTemplateColumn>
     
        <telerik:GridBoundColumn DataField="DayMar" HeaderText="Martedì">
        </telerik:GridBoundColumn>
        <telerik:GridTemplateColumn DataField="DayMer" HeaderText="Mercoledì">
            <ClientItemTemplate>
                <span> #=DayMer#</span>
            </ClientItemTemplate>
        </telerik:GridTemplateColumn>
        <telerik:GridBoundColumn DataField="DayGio" HeaderText="Giovedì">
        </telerik:GridBoundColumn>
        <telerik:GridBoundColumn DataField="DayVen" HeaderText="Venerdì">
        </telerik:GridBoundColumn>
    </Columns>

     

    - the schema of RadClientDataSource:

    <Schema ResponseType="JSON" >
        <Model>
            <telerik:ClientDataSourceModelField FieldName="Name" DataType="String" />
            <telerik:ClientDataSourceModelField FieldName="Type" DataType="String" />
     
            <telerik:ClientDataSourceModelField FieldName="DayLun"/>
            <telerik:ClientDataSourceModelField FieldName="DayLunId" />
            <telerik:ClientDataSourceModelField FieldName="DayLunCount" />
            <telerik:ClientDataSourceModelField FieldName="DayLunData" />
     
            <telerik:ClientDataSourceModelField FieldName="DayMar" />
            <telerik:ClientDataSourceModelField FieldName="DayMer" />
            <telerik:ClientDataSourceModelField FieldName="DayGio" />
            <telerik:ClientDataSourceModelField FieldName="DayVen" />
        </Model>
    </Schema>

     


    My RadGridParser.js (just the Parse function is changed):

    function Parse(sender, args) {
        var output = args.get_response().Output;
        if (output) {
            var model = {
                NomeFlusso: output.NomeFlusso,
                CodCompagnia: output.CodCompagnia,
                TipoFlusso: output.TipoFlusso,
     
                DayLun: output.DayLun,
                DayLunId: output.DayLun.Id,
                DayLunCount: output.DayLun.CountScarti,
                DayLunData: output.DayLun.Data,
     
                DayMar: JSON.stringify(output.DayMar),
                DayMer: JSON.stringify(output.DayMer),
                DayGio: JSON.stringify(output.DayGio),
                DayVen: JSON.stringify(output.DayVen)
            };
     
            args.set_parsedData(model);
        }
    }



    So, with this I have the situation that I showed in the attachment. I'm stuck.

    However I'm not obliged to do everything on the client.

     

     

  6. Marin
    Admin
    Marin avatar
    1045 posts

    Posted 11 May Link to this post

    Hello,

    I check the attached code and the result in the image. Indeed the GridTemplateColumn with ClientSideTemplate seems like the best approach here. The splitting of the model to separate fields for each day in the Parse function is also a suitable approach here, because it will allow access to each individual property in the client-side template:
    <ClientItemTemplate>
                <img src='Arrows-icon.png' alt="" style="vertical-align: middle; margin-right: 7px;" />
                <span>Id:#=DayLunId# </span>
                <span>(#=DayLunCount#)</span>
                <span>#=DayLunData#</span>
            </ClientItemTemplate>

    This is the approach that I had in mind in my previous post and it is the best for what the grid can offer at the moment for such type of data.
    Once you have access to each individual property in the template (DayLunId, DayLunCount, DayLunData), you can define the layout in your template in any preferred way and show the day as you like.
    The GridBoundColumn is not a good approach here, because it cannot automatically show the stringified JSON data in a suitable way, that's why you see something like "{CountScarti:50, "Data":null, "Id" : "5"}". In order to avoid this we recommend to use GridTemplateColumn with ClientSideTemplate for all the days in the data.
    In the template you don't have to show all the fields so if you leave only <span>(#=DayLunCount#)</span> and the image you have a layout similar to the one in the first attached picture in your post showing the preferred output.

    I hope this helps.

    Regards,
    Marin
    Telerik
    Do you need help with upgrading your ASP.NET AJAX, WPF or WinForms projects? Check the Telerik API Analyzer and share your thoughts.
  7. Gioce90
    Gioce90 avatar
    16 posts
    Member since:
    Nov 2015

    Posted 11 May in reply to Marin Link to this post

    Marin, starting from there I have changed again my source. In this way the code works, is much clear then before, but I don't understand some things... I have find a way to use objects in the ClientDataSource

     

    My code now is this:

     

    Model and web service are the sames.(I have just added some properties to the model..)

    My WebForm.aspx:
    - the columns of the RadGrid:

    <Columns>
        <telerik:GridBoundColumn DataField="Name" HeaderText="" DataType="System.String">
        </telerik:GridBoundColumn>
         
        <telerik:GridTemplateColumn DataField="Type" HeaderText="Tipologia flusso">
            <ClientItemTemplate>
                <span>#=showTipoFlusso(Type)#</span>
            </ClientItemTemplate>
        </telerik:GridTemplateColumn>
         
        <telerik:GridTemplateColumn DataField="DayLun" HeaderText="Lunedì">
            <ClientItemTemplate>
                #=showDetails(DayLun.Input, DayLun.Output, DayLun.Count)#
            </ClientItemTemplate>
        </telerik:GridTemplateColumn>
         
        ...
         
        <telerik:GridTemplateColumn DataField="DayVen" HeaderText="Venerdì">
            <ClientItemTemplate>
                #=showDetails(DayVen.Input, DayVen.Output, DayVen.Count)#
            </ClientItemTemplate>
        </telerik:GridTemplateColumn>
    </Columns>

     

    - the schema of RadClientDataSource:

    <Model>
        <telerik:ClientDataSourceModelField FieldName="NomeFlusso" DataType="String" OriginalFieldName="NomeFlusso"/>
        <telerik:ClientDataSourceModelField FieldName="TipoFlusso" DataType="Number" />
     
        <%-- DON'T PUT OBJECTS DECLARED in Parse( ) function!
        <telerik:ClientDataSourceModelField FieldName="DayLun" />
        <telerik:ClientDataSourceModelField FieldName="DayMar" />
        <telerik:ClientDataSourceModelField FieldName="DayMer" />
        <telerik:ClientDataSourceModelField FieldName="DayGio" />
        <telerik:ClientDataSourceModelField FieldName="DayVen" />--%>
    </Model>

     

    My RadGridParser.js:

    //<![CDATA[
     
    function ParameterMap(sender, args) {
        if (args.get_type() != "read" && args.get_data()) {
            args.set_parameterFormat({ request: kendo.stringify(args.get_data().models) });
        }
    }
     
     
    function Parse(sender, args) {
        var output = args.get_response().Output;
        if (output) {
         
            var model = {
                NomeFlusso: output.NomeFlusso,
                CodCompagnia: output.CodCompagnia,
                TipoFlusso: output.TipoFlusso,
     
                DayLun: {
                    Id: output.DayLun.Id,
                    Count: output.DayLun.CountScarti,
                    Data: output.DayLun.Data,
                    Input: output.DayLun.StatoFlussoInput,
                    Output: output.DayLun.StatoFlussoOutput
                },
                 
                DayMar: {
                    Id: output.DayMar.Id,
                    Count: output.DayMar.CountScarti,
                    Data: output.DayMar.Data,
                    Input: output.DayMar.StatoFlussoInput,
                    Output: output.DayMar.StatoFlussoOutput
                },
                 
                DayMer: {
                    Id: output.DayMer.Id,
                    Count: output.DayMer.CountScarti,
                    Data: output.DayMer.Data,
                    Input: output.DayMer.StatoFlussoInput,
                    Output: output.DayMer.StatoFlussoOutput
                },
                 
                DayGio: {
                    Id: output.DayGio.Id,
                    Count: output.DayGio.CountScarti,
                    Data: output.DayGio.Data,
                    Input: output.DayGio.StatoFlussoInput,
                    Output: output.DayGio.StatoFlussoOutput
                },
                 
                DayVen: {
                    Id: output.DayLun.Id,
                    Count: output.DayVen.CountScarti,
                    Data: output.DayVen.Data,
                    Input: output.DayVen.StatoFlussoInput,
                    Output: output.DayVen.StatoFlussoOutput
                }
            };
             
            args.set_parsedData(model);
        }
    }
     
     
    function UserAction(sender, args) {
        if (sender.get_batchEditingManager().hasChanges(sender.get_masterTableView()) &&
                    !confirm("Any changes will be cleared. Are you sure you want to perform this action?")) {
            args.set_cancel(true);
        }
    }
     
     
    /////////////////////////////
    // Stream Details functions:
     
     
    function showTipoFlusso(value) {
        // ...
        // return the correct string: "INPUT" or "OUTPUT" or "IN / OUT"
    }
     
    function showDetails(input, output, num) {
        //...
        // return the corrects html tags...
        return tags;
    }
     
    //]]>

     

    How you can see, I have done a lot of changes. The parser is better, I don't have a lot of field.

     

    My question is: way if I put something like:

    <telerik:ClientDataSourceModelField FieldName="DayLun" />

    in <Model> tag this doesn't works, but 

    <telerik:ClientDataSourceModelField FieldName="NomeFlusso" DataType="String" />

     works? I don't understand.

     

    If you need the rest of my code, just ask.

     

     

  8. Marin
    Admin
    Marin avatar
    1045 posts

    Posted 11 May Link to this post

    Hi,

    It doesn't work because DayLun is a complex object containing inner properties and the ClientDataSource is expecting a field of simple type like string, number, DateTime when defining the model fields. That was the idea behind splitting of the complex object to simple fields for each day like (DayLunId, DayLunCount, etc.) these are all simple types like string and number and can be set as field in the model of the ClientDataSource if necessary.
    If you don't set fields in the Model of the ClientDataSource it will still pass all the data from the Parse( ) method to the grid, so you can still use these nested complex object in the client template. However operations like filtering, sorting and editing on fields like DayLun will not be possible because it is a complex type containing multiple properties.

    Regards,
    Marin
    Telerik
    Do you need help with upgrading your ASP.NET AJAX, WPF or WinForms projects? Check the Telerik API Analyzer and share your thoughts.
Back to Top
UI for ASP.NET Ajax is Ready for VS 2017