Hierarchical grid - Custom OData query in childGrid

Hi,

I have a hierarchical grid with an OData data source :

@(Html.EJ().Grid<Contact>("ContactsGrid")
    .Datasource(ds => ds.URL("/odata/Contacts").CrossDomain(true))
    // ...
    .ClientSideEvents(evt => evt.Load("loadGridAction"))
    .Columns(col =>
    {
        col.Field("PartitionKey").Visible(false).Add();
        col.Field("RowKey").IsPrimaryKey(true).Visible(false).Type("string").Add();
        // ...
    })
    .ChildGrid<Toy>(child =>
    {
        child.Datasource(ds => ds.URL("/odata/Contacts/$RowKey/Toys").CrossDomain(true))
             .ClientSideEvents(evt => evt.Load("loadChildgrid"))
        // ...      
    })
)

By default an odata $filter is used to obtain the contact's toys, but I want to be more "odata" and query like "/odata/Contacts/ROWKEY/Toys", where ROWKEY is the key of the row that I opened.

How can this be done?

Thanks, 
Gaston

5 Replies

SE Sathyanarayanamoorthy Eswararao Syncfusion Team April 24, 2018 12:07 PM UTC

Hi Gaston, 

Thanks for contacting Syncfusion support. 

By default, in Odata adaptor when row is expanded the value of the queryString is passed in the URL to fetch the data corresponding to the queryString value. Please refer the below screenshot. 
 

Please provide the following details concerning your requirement. 

  1. Do you want to pass an additional parameter in the URL that is used to fetch the data for the child grid?
  2. Please share more details about your requirement.

We have prepared a sample with the Odata adaptor which can be downloaded from the below location. 


Regards, 
Sathyanarayanamoorthy 




GT Gaston TA April 26, 2018 07:00 AM UTC

Hi,

What I want to achieve is :
I have an odata endpoint .../Contacts. So
GET Contacts returns me a list of contacts.
GET Contacts('123') returns met 1 contact.

I have extended this endpoint so that contacts also have toys, such as

GET Contacts/123/Toys

This allows me to easily handle the 123 parameter in my code (a repository using Azure Tables).

So my question is:
how can I make the component call the second endpoint, instead of adding the $filter to the first one?
how can I parameterize the URI to be called as  GET Contacts/ CONTACTID / Toys?
and of course POST/PUT/DELETE in the same way, that is: PUT Contacts/123/Toys('abc') ... or a way to specify an endpoint for Toys('abc') for the PUT / DELETE operations.

If this is not possible then I will work around it. So that is an acceptable answer too :-)

Thanks in advance,
Gaston



SE Sathyanarayanamoorthy Eswararao Syncfusion Team April 27, 2018 12:37 PM UTC

Hi Gaston, 

We have analyzed your query and found that you need to access the Toys details corresponding to the ContactId ,by passing the ContactId to the Odatacontroller. This requirement can be achieved by the following method in the below code example. 

 
@(Html.EJ().Grid<object>("Editing") 
                  .Datasource(ds => { ds.URL("/odata/Products").Adaptor(AdaptorType.ODataV4Adaptor); }) 
 
          …... 
                       
        .Columns(col => 
        { 
            col.Field("ProductID").HeaderText("ProductID").IsPrimaryKey(true).IsIdentity(true).Width(50).Add(); 
            col.Field("SupplierID").HeaderText("SupplierID").Width(50).Add(); 
            col.Field("ProductName").HeaderText("ProductName").Width(50).Add(); 
 
        }) 
 
         .ChildGrid(d => 
         { 
           d.Datasource(ds => { ds.URL("/odata/Products(1)/Supplier").Adaptor(AdaptorType.ODataV4Adaptor); }) 
            .QueryString("SupplierID") 
             
            .Columns(col => 
            { 
                                     col.Field("SupplierID").HeaderText("SupplierID").IsPrimaryKey(true).IsIdentity(true).Width(50).Add(); 
                col.Field("CompanyName").HeaderText("CompanyName").Width(50).Add(); 
            }); 
         }) 
) 
 
[Controller.cs] 
 
   [Queryable] 
        public PageResult<Product> GetProducts(ODataQueryOptions opts) 
        { 
            List<Product> emp = db.Products.ToList(); 
 
 
            return new PageResult<Product>(opts.ApplyTo(emp.AsQueryable()) as IEnumerable<Product>, null, emp.AsQueryable().Count()); 
        } 
 
        // GET: odata/Products(5) 
        [Queryable] 
        public PageResult<Product> GetProduct([FromODataUri] int key, ODataQueryOptions opts) 
        { 
 
            IQueryable<Product> emp = db.Products.Where(m => m.ProductID == key); 
 
            return new PageResult<Product>(opts.ApplyTo(emp.AsQueryable()) as IEnumerable<Product>, null, emp.AsQueryable().Count()); 
        } 
 
            // GET: odata/Products(5)/Supplier 
        [Queryable] 
        public PageResult<Supplier> GetSupplier([FromODataUri] int key,ODataQueryOptions opts) 
    { 
            IQueryable<Supplier> emp = db.Products.Where(m => m.ProductID == key).Select(m => m.Supplier); 
 
            return new PageResult<Supplier>(opts.ApplyTo(emp.AsQueryable()) as IEnumerable<Supplier>, null, emp.AsQueryable().Count()); 
        } 
 

In the above code example the GET methods are accessed based on the parameters passed to the server. Please refer the below table for URL’s and it’s corresponding methods that are accessed on the server side. 
 
URL 
 
Corresponding Method 

odata/Products 

public PageResult<Product> GetProducts(ODataQueryOptions opts) 

odata/Products(5) 

        public PageResult<Product> GetProduct([FromODataUri] int key, ODataQueryOptions opts) 


odata/Products(5)/Supplier 
        public PageResult<Supplier> GetSupplier([FromODataUri] int key,ODataQueryOptions opts) 

In the above code example the Supplier items are accessed in the GetSupplier method based on the Key of the Product that is passed to  the server. These routing conventions and methods are explained in the below Microsoft help documentations. Similarly the PUT actions and DELETE Actions details are also explained in the below documentations. 

Please refer the below documentations for more details. 



If you need any further assistance please get back to us. 

Regards, 
Sathyanarayanamoorthy


GT Gaston TA April 27, 2018 01:08 PM UTC

Hi,

I'm afraid that I didn't communicate my questions good, so let me try to rephrase it.

The server-side (ODATA) is OK, I know how to handle that. But thanks for your example anyway!

On the client-side, using your example:
@(Html.EJ().Grid<object>("Editing") 
                  
.Datasource(ds => { ds.URL(
/Products"(AdaptorType.ODataV4Adaptor); }) 
 
          …... 
                       
        .Columns(col => 
        { 
            col.Field("ProductID").HeaderText("ProductID").IsPrimaryKey(true).IsIdentity(true).Width(50).Add(); 
            col.Field("SupplierID").HeaderText("SupplierID").Width(50).Add(); 
            col.Field("ProductName").HeaderText("ProductName").Width(50).Add(); 
 
        }) 
 
         .ChildGrid(d => 
         { 
           d.Datasource(ds => { ds.URL("/odata/Products(1)/Supplier").Adaptor(AdaptorType.ODataV4Adaptor); }) 
            .QueryString("SupplierID") 
             
            .Columns(col => 
            { 
                                     col.Field("SupplierID").HeaderText("SupplierID").IsPrimaryKey(true).IsIdentity(true).Width(50).Add(); 
                col.Field("CompanyName").HeaderText("CompanyName").Width(50).Add(); 
            }); 
         }) 
) 

The question here is: where you have /odata/Products(1)/Suppliers, I want to know how to parameterize the (1)
part so that it becomes the current productID from the parent grid.

This will allow me to indeed use  // GET: odata/Products(5)/Supplier 

In your example this would always be (1), not the value of the ProductID (unless I'm missing something).

So I would be very interested in knowing how to indicate this to the Grid control.

Thanks,
Gaston




SE Sathyanarayanamoorthy Eswararao Syncfusion Team April 30, 2018 12:45 PM UTC

Hi Gaston, 

Sorry for the inconvenience caused. 

According to your query you need to pass the current Id from the Parent Grid as parameter in the URL of the child Grid. We have achieved your requirement in the load event of the Child Grid. Please refer the below code example. 


 
@(Html.EJ().Grid<object>("Editing") 
                  .Datasource(ds => { ds.URL("/odata/Orders").Adaptor(AdaptorType.ODataV4Adaptor); }) 
                       
                   ….. 
 
       .Columns(col => 
        { 
            col.Field("OrderID").HeaderText("Order ID").IsPrimaryKey(true).IsIdentity(true).Width(50).Add(); 
            col.Field("EmployeeID").HeaderText("Employee ID").Width(50).Add(); 
            col.Field("ShipCity").HeaderText("ShipCity").Width(50).Add(); 
 
        }) 
 
         .ChildGrid(d => 
         { 
           d.Datasource(ds => { ds.URL("/odata/Orders").Adaptor(AdaptorType.ODataV4Adaptor); }) 
            .QueryString("EmployeeID") 
            .ClientSideEvents(eve => eve.Load("load") 
            .Columns(col => 
            { 
                col.Field("OrderID").HeaderText("Order ID").IsPrimaryKey(true).IsIdentity(true).Width(50).Add(); 
                col.Field("EmployeeID").HeaderText("Employee ID").Width(50).Add(); 
                col.Field("ShipCity").HeaderText("ShipCity").Width(50).Add(); 
            }); 
         }) 
 
) 
 
<script> 
    function load(args) { 
        args.model.dataSource.dataSource.url = "/odata/Orders(" + args.model.parentDetails.parentRowData.OrderID.toString() + ")" 
    } 
</script> 
 

In the above code example we have changed the URL of the Child Grid in the load event in which the parent Grid details are obtained in the args. 

Please refer the below documentation for details of Load event. 


If you need any further assistance please get back to us. 

Regards, 
Sathyanarayanamoorthy 


Loader.
Up arrow icon