In an earlier post I described how to display Master Detail data with TagHelpers when all data is present on client. In this article, I'll describe the steps needed to display data from related tables when the data may reside on server.
See currency in action.

I've created a new project using the "C1 ASP.NET MVC 6 Web Application" template. This automatically configures the project with all the packages and resource registrations.

MVC6 Template

For detail on using default MVC 6 template please refer to the documentation.

The Data


The data for this example comes from the Northwind database. I'm using Entity Framework to get the Customers and Orders data. The two tables are related by CustomerID column, as each customer may have placed many orders.

Provide the Data


Here I list the controller actions that serve the Customer and related Orders data.


public partial class FlexGridController : Controller
{
// GET: /<controller>/
public ActionResult MasterDetail()
{
return View(_db.Customers.Take(10).ToList()); // _db is an instance of C1NWindEntities
}

public ActionResult DetailData([C1JsonRequest] CollectionViewRequest<Order> requestData)
{
string customerID = requestData.ExtraRequestData["CustomerID"].ToString(); //get the current selected Customer.
return this.C1Json(CollectionViewHelper.Read(requestData, _db.Orders.Where(s => s.CustomerID == customerID).ToList()));
}
}


In the "MasterDetail" action we're returning 10 customers to the View. In the "DetailData" action, first we're getting the CustomerID for which the detail has been requested. Then we're returning the related Orders by comparing and getting only those orders which were placed by this "CustomerID".

Show Me The Data


Let's start configuring the view by initialising FlexGrid to display Customer data.

@using TagHelperExplorer.Models
@using C1.Web.Mvc.Grid
@model IEnumerable<Customer>

<div>Customers</div>
<c1-flex-grid id="Customer" auto-generate-columns="false" is-read-only="true" selection-mode="SelectionMode.Row">
<c1-flex-grid-column binding="CustomerID" width="*"></c1-flex-grid-column>
<c1-flex-grid-column binding="CompanyName" width="2*"></c1-flex-grid-column>
<c1-flex-grid-column binding="Country" width="2*"></c1-flex-grid-column>
<c1-flex-grid-column binding="City" width="2*"></c1-flex-grid-column>
<c1-items-source source-collection="Model"></c1-items-source>
</c1-flex-grid>


Next, we'll initialise another FlexGrid to display Order data:

<div>Orders</div>
<c1-flex-grid id="Orders" auto-generate-columns="true" is-read-only="true">
<c1-items-source read-action-url="@Url.Action("DetailData")" collecting-query-data="getCustomerID"></c1-items-source>
</c1-flex-grid>


It's interesting to note the binding of "Orders" FlexGrid: it has a collection-query-data tag that takes a javascript function that returns "CustomerID" for which orders need to be displayed.

Here's the "getCustomerID" javascript function:

function getCustomerID(sender, e) {
if (e.extraRequestData == null) {
e.extraRequestData = {};
}
grid = wijmo.Control.getControl("#Customer"); //Get the reference for "Customers" FlexGrid
if (grid) {
currentItem = grid.collectionView.currentItem; //Get the selected Customer in Customers FlexGrid
e.extraRequestData["CustomerID"] = currentItem ? currentItem.CustomerID : ""; //assign CustomerID to return argument
}


This function returns the "CustomerID" of the current selected Customer in "Customer" FlexGrid. This, however, does not solve our problem. We want to display related orders when selection changes. This requires some currency to be tracked, and we can achieve this by refreshing the "Orders" FlexGrid "collectionView" when the current selection changes for the "Customers" FlexGrid. The collectionView can be refreshed in the "currentChanged" event handler of "Customer" FlexGrid's collectionView.


var grid, cv,detail,cvDetail;
c1.mvc.Utils.documentReady(function () {
grid = wijmo.Control.getControl("#Customer"); //Get reference for Customers FlexGrid
cv = grid.collectionView; //Get reference for Customers FlexGrid collectionView
cv.currentChanged.addHandler(getOrders); //Add handler to Customers FlexGrid collectionView
cv.moveCurrentToFirst();
});

function getOrders() {
detail = wijmo.Control.getControl("#Orders");
if (cvDetail == null)
{
cvDetail = detail.collectionView; //Get reference for Orders FlexGrid collectionView
}

cvDetail.refresh(); //refresh the collectionView so that it performs a full refresh of the data.
}


Here's the complete script:

<script type="text/javascript">
var grid, cv,detail,cvDetail;
c1.mvc.Utils.documentReady(function () {
grid = wijmo.Control.getControl("#Customer");
cv = grid.collectionView;
cv.currentChanged.addHandler(getOrders);
cv.moveCurrentToFirst();
});

function getOrders() {
detail = wijmo.Control.getControl("#Orders");
if (cvDetail == null)
{
cvDetail = detail.collectionView;
}

cvDetail.refresh();
}

function getCustomerID(sender, e) {
if (e.extraRequestData == null) {
e.extraRequestData = {};
}
grid = wijmo.Control.getControl("#Customer");
if (grid) {
currentItem = grid.collectionView.currentItem;
e.extraRequestData["CustomerID"] = currentItem ? currentItem.CustomerID : "";
}
}
</script>


Here's the complete code for the View:



@using TagHelperExplorer.Models
@using C1.Web.Mvc.Grid
@model IEnumerable<Customer>

<script type="text/javascript">
var grid, cv,detail,cvDetail;
c1.mvc.Utils.documentReady(function () {
grid = wijmo.Control.getControl("#Customer");
cv = grid.collectionView;
cv.currentChanged.addHandler(getOrders);
cv.moveCurrentToFirst();
});

function getOrders() {
detail = wijmo.Control.getControl("#Orders");
if (cvDetail == null)
{
cvDetail = detail.collectionView;
}

cvDetail.refresh();
}

function getCustomerID(sender, e) {
if (e.extraRequestData == null) {
e.extraRequestData = {};
}
grid = wijmo.Control.getControl("#Customer");
if (grid) {
currentItem = grid.collectionView.currentItem;
e.extraRequestData["CustomerID"] = currentItem ? currentItem.CustomerID : "";
}
}
</script>
<div>Customers</div>
<c1-flex-grid id="Customer" auto-generate-columns="false" is-read-only="true" selection-mode="SelectionMode.Row">
<c1-flex-grid-column binding="CustomerID" width="*"></c1-flex-grid-column>
<c1-flex-grid-column binding="CompanyName" width="2*"></c1-flex-grid-column>
<c1-flex-grid-column binding="Country" width="2*"></c1-flex-grid-column>
<c1-flex-grid-column binding="City" width="2*"></c1-flex-grid-column>

<c1-items-source source-collection="Model"></c1-items-source>
</c1-flex-grid>
<div>Orders</div>
<c1-flex-grid id="Orders" auto-generate-columns="true" is-read-only="true">
<c1-items-source read-action-url="@Url.Action("DetailData")" collecting-query-data="getCustomerID"></c1-items-source>
</c1-flex-grid>


This implementation is also possible with HtmlHelpers in MVC 3,4,5. Most of the code would remain the same except how the FlexGrid is declared. We'll add this example to MVCExplorer sample for easy reference.


Please note TagHelpers are a work in progress. You'll be able to try out these controls in MVC6 with Beta7 support in September 2015.

Read more about TagHelpers in ASP.NET MVC Edition >>


Read more about ComponentOne Studio MVC Edition>>